keycloak-aplcache
Changes
dependencies/server-all/pom.xml 7(+6 -1)
distribution/feature-packs/server-feature-pack/src/main/resources/content/bin/federation-sssd-setup.sh 31(+31 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-services/main/module.xml 1(+1 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-sssd-federation/main/module.xml 32(+32 -0)
federation/pom.xml 1(+1 -0)
federation/sssd/pom.xml 56(+56 -0)
federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/DBusExecutionException.java 39(+39 -0)
federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/InternalMessageException.java 18(+18 -0)
federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/MessageFormatException.java 21(+21 -0)
federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/MessageProtocolVersionException.java 20(+20 -0)
federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/UnknownTypeCodeException.java 20(+20 -0)
federation/sssd/src/main/java/org/keycloak/federation/sssd/ReadonlySSSDUserModelDelegate.java 77(+77 -0)
federation/sssd/src/main/java/org/keycloak/federation/sssd/SSSDFederationProviderFactory.java 88(+29 -59)
federation/sssd/src/main/resources/DBUS-JAVA-LICENSE 680(+680 -0)
federation/sssd/src/main/resources/META-INF/services/org.keycloak.models.UserFederationProviderFactory 18(+18 -0)
pom.xml 12(+12 -0)
testsuite/integration/pom.xml 8(+8 -0)
testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractKeycloakIdentityProviderTest.java 2(+1 -1)
testsuite/integration/src/test/java/org/keycloak/testsuite/DummyUserFederationProvider.java 150(+0 -150)
testsuite/integration/src/test/java/org/keycloak/testsuite/federation/sync/SyncDummyUserFederationProviderFactory.java 2(+1 -1)
testsuite/integration/src/test/java/org/keycloak/testsuite/federation/sync/SyncFederationTest.java 2(+1 -1)
testsuite/integration/src/test/java/org/keycloak/testsuite/model/ConcurrentTransactionsTest.java 18(+14 -4)
testsuite/integration/src/test/resources/META-INF/services/org.keycloak.models.UserFederationProviderFactory 1(+0 -1)
testsuite/integration-arquillian/servers/auth-server/jboss/common/keycloak-server-subsystem.xsl 13(+13 -0)
testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/META-INF/keycloak-themes.json 6(+6 -0)
testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/account/account.ftl 114(+114 -0)
testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/account/theme.properties 18(+18 -0)
testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/admin/resources/partials/user-attributes.html 72(+72 -0)
testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/admin/theme.properties 18(+18 -0)
testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/login/login-update-profile.ftl 95(+95 -0)
testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/login/register.ftl 131(+131 -0)
testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/login/theme.properties 18(+18 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/AccountUpdateProfilePage.java 20(+20 -0)
Details
diff --git a/adapters/oidc/js/src/main/resources/keycloak.js b/adapters/oidc/js/src/main/resources/keycloak.js
index c6adb9b..44a7e75 100755
--- a/adapters/oidc/js/src/main/resources/keycloak.js
+++ b/adapters/oidc/js/src/main/resources/keycloak.js
@@ -154,7 +154,7 @@
                     return;
                 } else if (initOptions) {
                     if (initOptions.token || initOptions.refreshToken) {
-                        setToken(initOptions.token, initOptions.refreshToken, initOptions.idToken, false);
+                        setToken(initOptions.token, initOptions.refreshToken, initOptions.idToken);
                         kc.timeSkew = initOptions.timeSkew || 0;
 
                         if (loginIframe.enable) {
@@ -406,10 +406,10 @@
                                     timeLocal = (timeLocal + new Date().getTime()) / 2;
 
                                     var tokenResponse = JSON.parse(req.responseText);
-                                    setToken(tokenResponse['access_token'], tokenResponse['refresh_token'], tokenResponse['id_token'], true);
-
                                     kc.timeSkew = Math.floor(timeLocal / 1000) - kc.tokenParsed.iat;
 
+                                    setToken(tokenResponse['access_token'], tokenResponse['refresh_token'], tokenResponse['id_token']);
+
                                     kc.onAuthRefreshSuccess && kc.onAuthRefreshSuccess();
                                     for (var p = refreshQueue.pop(); p != null; p = refreshQueue.pop()) {
                                         p.setSuccess(true);
@@ -444,7 +444,7 @@
 
         kc.clearToken = function() {
             if (kc.token) {
-                setToken(null, null, null, true);
+                setToken(null, null, null);
                 kc.onAuthLogout && kc.onAuthLogout();
                 if (kc.loginRequired) {
                     kc.login();
@@ -525,7 +525,7 @@
             function authSuccess(accessToken, refreshToken, idToken, fulfillPromise) {
                 timeLocal = (timeLocal + new Date().getTime()) / 2;
 
-                setToken(accessToken, refreshToken, idToken, true);
+                setToken(accessToken, refreshToken, idToken);
 
                 if ((kc.tokenParsed && kc.tokenParsed.nonce != oauth.storedNonce) ||
                     (kc.refreshTokenParsed && kc.refreshTokenParsed.nonce != oauth.storedNonce) ||
@@ -609,7 +609,7 @@
             return promise.promise;
         }
 
-        function setToken(token, refreshToken, idToken, useTokenTime) {
+        function setToken(token, refreshToken, idToken) {
             if (kc.tokenTimeoutHandle) {
                 clearTimeout(kc.tokenTimeoutHandle);
                 kc.tokenTimeoutHandle = null;
@@ -629,9 +629,12 @@
                 kc.resourceAccess = kc.tokenParsed.resource_access;
 
                 if (kc.onTokenExpired) {
-                    var start = useTokenTime ? kc.tokenParsed.iat : (new Date().getTime() / 1000);
-                    var expiresIn = kc.tokenParsed.exp - start;
-                    kc.tokenTimeoutHandle = setTimeout(kc.onTokenExpired, expiresIn * 1000);
+                    var expiresIn = (kc.tokenParsed['exp'] - (new Date().getTime() / 1000) + kc.timeSkew) * 1000;
+                    if (expiresIn <= 0) {
+                        kc.onTokenExpired();
+                    } else {
+                        kc.tokenTimeoutHandle = setTimeout(kc.onTokenExpired, expiresIn);
+                    }
                 }
 
             } else {
                dependencies/server-all/pom.xml 7(+6 -1)
diff --git a/dependencies/server-all/pom.xml b/dependencies/server-all/pom.xml
index 809890a..8922532 100755
--- a/dependencies/server-all/pom.xml
+++ b/dependencies/server-all/pom.xml
@@ -83,7 +83,6 @@
             <groupId>org.keycloak</groupId>
             <artifactId>keycloak-kerberos-federation</artifactId>
         </dependency>
-
         <!-- saml -->
         <dependency>
             <groupId>org.keycloak</groupId>
@@ -110,6 +109,12 @@
             </exclusions>
         </dependency>
 
+        <!-- Dependencies for RHEL IdM -->
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-sssd-federation</artifactId>
+        </dependency>
+
         <!-- Built-in Authorization Policy Providers  -->
         <dependency>
             <groupId>org.keycloak</groupId>
                diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/content/bin/federation-sssd-setup.sh b/distribution/feature-packs/server-feature-pack/src/main/resources/content/bin/federation-sssd-setup.sh
new file mode 100644
index 0000000..6a0eae2
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/content/bin/federation-sssd-setup.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+# Setup for SSSD
+SSSD_FILE="/etc/sssd/sssd.conf"
+
+if [ -f "$SSSD_FILE" ];
+then
+  sed -i '/ldap_tls_cacert/a ldap_user_extra_attrs = mail:mail, sn:sn, givenname:givenname, telephoneNumber:telephoneNumber' $SSSD_FILE
+  sed -i 's/nss, sudo, pam/nss, sudo, pam, ifp/' $SSSD_FILE
+  sed -i '/\[ifp\]/a allowed_uids = root\nuser_attributes = +mail, +telephoneNumber, +givenname, +sn' $SSSD_FILE
+  systemctl restart sssd
+else
+  echo "Please make sure you have $SSSD_FILE into your system! Aborting."
+  exit 1
+fi
+
+# Setup for PAM
+PAM_FILE="/etc/pam.d/keycloak"
+
+if [ ! -f "$PAM_FILE" ];
+then
+cat <<EOF > $PAM_FILE
+  auth    required   pam_sss.so
+  account required   pam_sss.so
+EOF
+else
+  echo "$PAM_FILE already exists. Skipping it..."
+  exit 0
+fi
+
+
                diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-services/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-services/main/module.xml
index de03ed8..8cf1cde 100755
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-services/main/module.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-services/main/module.xml
@@ -35,6 +35,7 @@
         <module name="org.keycloak.keycloak-js-adapter" services="import"/>
         <module name="org.keycloak.keycloak-kerberos-federation" services="import"/>
         <module name="org.keycloak.keycloak-ldap-federation" services="import"/>
+        <module name="org.keycloak.keycloak-sssd-federation" services="import"/>
         <module name="org.keycloak.keycloak-server-spi" services="import"/>
         <module name="org.keycloak.keycloak-model-jpa" services="import"/>
         <module name="org.keycloak.keycloak-model-mongo" services="import"/>
                diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-sssd-federation/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-sssd-federation/main/module.xml
new file mode 100644
index 0000000..ad16f3c
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-sssd-federation/main/module.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<module xmlns="urn:jboss:module:1.3" name="org.keycloak.keycloak-sssd-federation">
+    <properties>
+        <property name="jboss.api" value="private"/>
+    </properties>
+
+    <resources>
+        <artifact name="${org.keycloak:keycloak-sssd-federation}"/>
+    </resources>
+
+    <dependencies>
+        <module name="org.jboss.logging"/>
+        <module name="org.keycloak.keycloak-core" />
+        <module name="org.keycloak.keycloak-server-spi" />
+    </dependencies>
+</module>
\ No newline at end of file
                federation/pom.xml 1(+1 -0)
diff --git a/federation/pom.xml b/federation/pom.xml
index 663f857..dc702cc 100755
--- a/federation/pom.xml
+++ b/federation/pom.xml
@@ -35,6 +35,7 @@
     <modules>
         <module>ldap</module>
         <module>kerberos</module>
+        <module>sssd</module>
     </modules>
 
 </project>
                federation/sssd/pom.xml 56(+56 -0)
diff --git a/federation/sssd/pom.xml b/federation/sssd/pom.xml
new file mode 100644
index 0000000..7d109e8
--- /dev/null
+++ b/federation/sssd/pom.xml
@@ -0,0 +1,56 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <parent>
+        <artifactId>keycloak-parent</artifactId>
+        <groupId>org.keycloak</groupId>
+        <version>2.2.0-SNAPSHOT</version>
+        <relativePath>../../pom.xml</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>keycloak-sssd-federation</artifactId>
+    <name>Keycloak SSSD Federation</name>
+    <description/>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>${maven.compiler.source}</source>
+                    <target>${maven.compiler.target}</target>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>net.java.dev.jna</groupId>
+            <artifactId>jna</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-server-spi</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.logging</groupId>
+            <artifactId>jboss-logging</artifactId>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+</project>
                diff --git a/federation/sssd/src/main/java/cx/ath/matthew/debug/Debug.java b/federation/sssd/src/main/java/cx/ath/matthew/debug/Debug.java
new file mode 100644
index 0000000..30c4d85
--- /dev/null
+++ b/federation/sssd/src/main/java/cx/ath/matthew/debug/Debug.java
@@ -0,0 +1,671 @@
+/* Copyright (C) 1991-2015 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library 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.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+/* This header is separate from features.h so that the compiler can
+   include it implicitly at the start of every compilation.  It must
+   not itself include <features.h> or any other header that includes
+   <features.h> because the implicit include comes before any feature
+   test macros that may be defined in a source file before it first
+   explicitly includes a system header.  GCC knows the name of this
+   header in order to preinclude it.  */
+/* glibc's intent is to support the IEC 559 math functionality, real
+   and complex.  If the GCC (4.9 and later) predefined macros
+   specifying compiler intent are available, use them to determine
+   whether the overall intent is to support these features; otherwise,
+   presume an older compiler has intent to support these features and
+   define these macros by default.  */
+/* wchar_t uses Unicode 7.0.0.  Version 7.0 of the Unicode Standard is
+   synchronized with ISO/IEC 10646:2012, plus Amendments 1 (published
+   on April, 2013) and 2 (not yet published as of February, 2015).
+   Additionally, it includes the accelerated publication of U+20BD
+   RUBLE SIGN.  Therefore Unicode 7.0.0 is between 10646:2012 and
+   10646:2014, and so we use the date ISO/IEC 10646:2012 Amd.1 was
+   published.  */
+/* We do not support C11 <threads.h>.  */
+/*
+ * Java Debug Library
+ *
+ * Copyright (c) Matthew Johnson 2005
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * To Contact the author, please email src@matthew.ath.cx
+ *
+ */
+package cx.ath.matthew.debug;
+
+import cx.ath.matthew.utils.Hexdump;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * Add debugging to your program, has support for large projects with multiple
+ * classes and debug levels per class. Supports optional enabling of debug
+ * per-level per-class and debug targets of files, Streams or stderr.
+ * Also supports timing between debug outputs, printing of stack traces for Throwables
+ * and files/line numbers on each message.
+ * <p>
+ * Debug now automatically figures out which class it was called from, so all
+ * methods passing in the calling class are deprecated.
+ * </p>
+ * <p>
+ * The defaults are to print all messages to stderr with class and method name.
+ * </p>
+ * <p>
+ * Should be called like this:
+ * </p>
+ * <pre>
+ * if (Debug.debug) Debug.print(Debug.INFO, "Debug Message");
+ * </pre>
+ */
+public class Debug {
+    /**
+     * This interface can be used to provide custom printing filters
+     * for certain classes.
+     */
+    public static interface FilterCommand {
+        /**
+         * Called to print debug messages with a custom filter.
+         *
+         * @param output   The PrintStream to output to.
+         * @param level    The debug level of this message.
+         * @param location The textual location of the message.
+         * @param extra    Extra information such as timing details.
+         * @param message  The debug message.
+         * @param lines    Other lines of a multiple-line debug message.
+         */
+        public void filter(PrintStream output, int level, String location, String extra, String message, String[] lines);
+    }
+
+    /**
+     * Highest priority messages
+     */
+    public static final int CRIT = 1;
+    /**
+     * Error messages
+     */
+    public static final int ERR = 2;
+    /**
+     * Warnings
+     */
+    public static final int WARN = 3;
+    /**
+     * Information
+     */
+    public static final int INFO = 4;
+    /**
+     * Debug messages
+     */
+    public static final int DEBUG = 5;
+    /**
+     * Verbose debug messages
+     */
+    public static final int VERBOSE = 6;
+    /**
+     * Set this to false to disable compilation of Debug statements
+     */
+    public static final boolean debug = false;
+    /**
+     * The current output stream (defaults to System.err)
+     */
+    public static PrintStream debugout = System.err;
+    private static Properties prop = null;
+    private static boolean timing = false;
+    private static boolean ttrace = false;
+    private static boolean lines = false;
+    private static boolean hexdump = false;
+    private static long last = 0;
+    private static int balen = 36;
+    private static int bawidth = 80;
+    private static Class saveclass = null;
+    //TODO: 1.5 private static Map<Class<? extends Object>, FilterCommand> filterMap = new HashMap<Class<? extends Object>, FilterCommand>();
+    private static Map filterMap = new HashMap();
+
+    /**
+     * Set properties to configure debugging.
+     * Format of properties is class => level, e.g.
+     * <pre>
+     * cx.ath.matthew.io.TeeOutputStream = INFO
+     * cx.ath.matthew.io.DOMPrinter = DEBUG
+     * </pre>
+     * The debug level can be one of CRIT, ERR, WARN, INFO, DEBUG or VERBOSE which
+     * correspond to all messages up to that level. The special words YES, ALL and TRUE
+     * cause all messages to be printed regardless of level. All other terms disable
+     * messages for that class. CRIT and ERR messages are always printed if debugging is enabled
+     * unless explicitly disabled.
+     * The special class name ALL can be used to set the default level for all classes.
+     *
+     * @param prop Properties object to use.
+     */
+    public static void setProperties(Properties prop) {
+        Debug.prop = prop;
+    }
+
+    /**
+     * Read which class to debug on at which level from the given File.
+     * Syntax the same as Java Properties files:
+     * <pre>
+     * <class> = <debuglevel>
+     * </pre>
+     * E.G.
+     * <pre>
+     * cx.ath.matthew.io.TeeOutputStream = INFO
+     * cx.ath.matthew.io.DOMPrinter = DEBUG
+     * </pre>
+     * The debug level can be one of CRIT, ERR, WARN, INFO, DEBUG or VERBOSE which
+     * correspond to all messages up to that level. The special words YES, ALL and TRUE
+     * cause all messages to be printed regardless of level. All other terms disable
+     * messages for that class. CRIT and ERR messages are always printed if debugging is enabled
+     * unless explicitly disabled.
+     * The special class name ALL can be used to set the default level for all classes.
+     *
+     * @param f File to read from.
+     */
+    public static void loadConfig(File f) throws IOException {
+        prop = new Properties();
+        prop.load(new FileInputStream(f));
+    }
+
+    /**
+     * @deprecated In Java 1.5 calling class is automatically identified, no need to pass it in.
+     */
+    //TODO: 1.5 @Deprecated()
+    public static boolean debugging(Class c, int loglevel) {
+        if (debug) {
+            if (null == c) return true;
+            return debugging(c.getName(), loglevel);
+        }
+        return false;
+    }
+
+    public static boolean debugging(String s, int loglevel) {
+        if (debug) {
+            try {
+                if (null == s) return true;
+                if (null == prop) return loglevel <= DEBUG;
+                String d = prop.getProperty(s);
+                if (null == d || "".equals(d)) d = prop.getProperty("ALL");
+                if (null == d) return loglevel <= ERR;
+                if ("".equals(d)) return loglevel <= ERR;
+                d = d.toLowerCase();
+                if ("true".equals(d)) return true;
+                if ("yes".equals(d)) return true;
+                if ("all".equals(d)) return true;
+                if ("verbose".equals(d)) return loglevel <= VERBOSE;
+                if ("debug".equals(d)) return loglevel <= DEBUG;
+                if ("info".equals(d)) return loglevel <= INFO;
+                if ("warn".equals(d)) return loglevel <= WARN;
+                if ("err".equals(d)) return loglevel <= ERR;
+                if ("crit".equals(d)) return loglevel <= CRIT;
+                int i = Integer.parseInt(d);
+                return i >= loglevel;
+            } catch (Exception e) {
+                return false;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Output to the given Stream
+     */
+    public static void setOutput(PrintStream p) throws IOException {
+        debugout = p;
+    }
+
+    /**
+     * Output to the given file
+     */
+    public static void setOutput(String filename) throws IOException {
+        debugout = new PrintStream(new FileOutputStream(filename, true));
+    }
+
+    /**
+     * Output to the default debug.log
+     */
+    public static void setOutput() throws IOException {
+        setOutput("./debug.log");
+    }
+
+    /**
+     * Log at DEBUG
+     *
+     * @param d The object to log
+     */
+    public static void print(Object d) {
+        if (debug) {
+            if (d instanceof String)
+                print(DEBUG, (String) d);
+            else if (d instanceof Throwable)
+                print(DEBUG, (Throwable) d);
+            else if (d instanceof byte[])
+                print(DEBUG, (byte[]) d);
+            else if (d instanceof Map)
+                printMap(DEBUG, (Map) d);
+            else print(DEBUG, d);
+        }
+    }
+
+    /**
+     * Log at DEBUG
+     *
+     * @param o The object doing the logging
+     * @param d The object to log
+     * @deprecated In Java 1.5 calling class is automatically identified, no need to pass it in.
+     */
+    //TODO: 1.5 @Deprecated()
+    public static void print(Object o, Object d) {
+        if (debug) {
+            if (o instanceof Class)
+                saveclass = (Class) o;
+            else
+                saveclass = o.getClass();
+            print(d);
+        }
+    }
+
+    /**
+     * Log an Object
+     *
+     * @param o        The object doing the logging
+     * @param loglevel The level to log at (DEBUG, WARN, etc)
+     * @param d        The object to log with d.toString()
+     * @deprecated In Java 1.5 calling class is automatically identified, no need to pass it in.
+     */
+    //TODO: 1.5 @Deprecated()
+    public static void print(Object o, int loglevel, Object d) {
+        if (debug) {
+            if (o instanceof Class)
+                saveclass = (Class) o;
+            else
+                saveclass = o.getClass();
+            print(loglevel, d);
+        }
+    }
+
+    /**
+     * Log a String
+     *
+     * @param o        The object doing the logging
+     * @param loglevel The level to log at (DEBUG, WARN, etc)
+     * @param s        The log message
+     * @deprecated In Java 1.5 calling class is automatically identified, no need to pass it in.
+     */
+    //TODO: 1.5 @Deprecated()
+    public static void print(Object o, int loglevel, String s) {
+        if (debug) {
+            if (o instanceof Class)
+                saveclass = (Class) o;
+            else
+                saveclass = o.getClass();
+            print(loglevel, s);
+        }
+    }
+
+    /**
+     * Log a Throwable
+     *
+     * @param o        The object doing the logging
+     * @param loglevel The level to log at (DEBUG, WARN, etc)
+     * @param t        The throwable to log with .toString and .printStackTrace
+     * @deprecated In Java 1.5 calling class is automatically identified, no need to pass it in.
+     */
+    //TODO: 1.5 @Deprecated()
+    public static void print(Object o, int loglevel, Throwable t) {
+        if (debug) {
+            if (o instanceof Class)
+                saveclass = (Class) o;
+            else
+                saveclass = o.getClass();
+            print(loglevel, t);
+        }
+    }
+
+    /**
+     * Log a Throwable
+     *
+     * @param c        The class doing the logging
+     * @param loglevel The level to log at (DEBUG, WARN, etc)
+     * @param t        The throwable to log with .toString and .printStackTrace
+     * @deprecated In Java 1.5 calling class is automatically identified, no need to pass it in.
+     */
+    //TODO: 1.5 @Deprecated()
+    public static void print(Class c, int loglevel, Throwable t) {
+        if (debug) {
+            saveclass = c;
+            print(loglevel, t);
+        }
+    }
+
+    /**
+     * Log a Throwable
+     *
+     * @param loglevel The level to log at (DEBUG, WARN, etc)
+     * @param t        The throwable to log with .toString and .printStackTrace
+     * @see #setThrowableTraces to turn on stack traces.
+     */
+    public static void print(int loglevel, Throwable t) {
+        if (debug) {
+            String timestr = "";
+            String[] data = getTraceElements();
+            if (debugging(data[0], loglevel)) {
+                if (timing) {
+                    long now = System.currentTimeMillis();
+                    timestr = "{" + (now - last) + "} ";
+                    last = now;
+                }
+                String[] lines = null;
+                if (ttrace) {
+                    StackTraceElement[] ste = t.getStackTrace();
+                    lines = new String[ste.length];
+                    for (int i = 0; i < ste.length; i++)
+                        lines[i] = "\tat " + ste[i].toString();
+                }
+                _print(t.getClass(), loglevel, data[0] + "." + data[1] + "()" + data[2], timestr, t.toString(), lines);
+            }
+        }
+    }
+
+    /**
+     * Log a byte array
+     *
+     * @param loglevel The level to log at (DEBUG, WARN, etc)
+     * @param b        The byte array to print.
+     * @see #setHexDump to enable hex dumping.
+     * @see #setByteArrayCount to change how many bytes are printed.
+     * @see #setByteArrayWidth to change the formatting width of hex.
+     */
+    public static void print(int loglevel, byte[] b) {
+        if (debug) {
+            String timestr = "";
+            String[] data = getTraceElements();
+            if (debugging(data[0], loglevel)) {
+                if (timing) {
+                    long now = System.currentTimeMillis();
+                    timestr = "{" + (now - last) + "} ";
+                    last = now;
+                }
+                String[] lines = null;
+                if (hexdump) {
+                    if (balen >= b.length)
+                        lines = Hexdump.format(b, bawidth).split("\n");
+                    else {
+                        byte[] buf = new byte[balen];
+                        System.arraycopy(b, 0, buf, 0, balen);
+                        lines = Hexdump.format(buf, bawidth).split("\n");
+                    }
+                }
+                _print(b.getClass(), loglevel, data[0] + "." + data[1] + "()" + data[2], timestr, b.length + " bytes", lines);
+            }
+        }
+    }
+
+    /**
+     * Log a String
+     *
+     * @param loglevel The level to log at (DEBUG, WARN, etc)
+     * @param s        The string to log with d.toString()
+     */
+    public static void print(int loglevel, String s) {
+        if (debug)
+            print(loglevel, (Object) s);
+    }
+
+    /**
+     * Log an Object
+     *
+     * @param c        The class doing the logging
+     * @param loglevel The level to log at (DEBUG, WARN, etc)
+     * @param d        The object to log with d.toString()
+     * @deprecated In Java 1.5 calling class is automatically identified, no need to pass it in.
+     */
+    //TODO: 1.5 @Deprecated()
+    public static void print(Class c, int loglevel, Object d) {
+        if (debug) {
+            saveclass = c;
+            print(loglevel, d);
+        }
+    }
+
+    /**
+     * Log a String
+     *
+     * @param c        The class doing the logging
+     * @param loglevel The level to log at (DEBUG, WARN, etc)
+     * @param s        The log message
+     * @deprecated In Java 1.5 calling class is automatically identified, no need to pass it in.
+     */
+    //TODO: 1.5 @Deprecated()
+    public static void print(Class c, int loglevel, String s) {
+        if (debug) {
+            saveclass = c;
+            print(loglevel, s);
+        }
+    }
+
+    private static String[] getTraceElements() {
+        String[] data = new String[]{"", "", ""};
+        try {
+            Method m = Thread.class.getMethod("getStackTrace", new Class[0]);
+            StackTraceElement[] stes = (StackTraceElement[]) m.invoke(Thread.currentThread(), new Object[0]);
+            for (StackTraceElement ste : stes) {
+                if (Debug.class.getName().equals(ste.getClassName())) continue;
+                if (Thread.class.getName().equals(ste.getClassName())) continue;
+                if (Method.class.getName().equals(ste.getClassName())) continue;
+                if (ste.getClassName().startsWith("sun.reflect")) continue;
+                data[0] = ste.getClassName();
+                data[1] = ste.getMethodName();
+                if (lines)
+                    data[2] = " " + ste.getFileName() + ":" + ste.getLineNumber();
+                break;
+            }
+        } catch (NoSuchMethodException NSMe) {
+            if (null != saveclass)
+                data[0] = saveclass.getName();
+        } catch (IllegalAccessException IAe) {
+        } catch (InvocationTargetException ITe) {
+        }
+        return data;
+    }
+
+    /**
+     * Log an Object
+     *
+     * @param loglevel The level to log at (DEBUG, WARN, etc)
+     * @param o        The object to log
+     */
+    public static void print(int loglevel, Object o) {
+        if (debug) {
+            String timestr = "";
+            String[] data = getTraceElements();
+            if (debugging(data[0], loglevel)) {
+                if (timing) {
+                    long now = System.currentTimeMillis();
+                    timestr = "{" + (now - last) + "} ";
+                    last = now;
+                }
+                _print(o.getClass(), loglevel, data[0] + "." + data[1] + "()" + data[2], timestr, o.toString(), null);
+            }
+        }
+    }
+
+    /**
+     * Log a Map
+     *
+     * @param o        The object doing the logging
+     * @param loglevel The level to log at (DEBUG, WARN, etc)
+     * @param m        The Map to print out
+     * @deprecated In Java 1.5 calling class is automatically identified, no need to pass it in.
+     */
+    //TODO: 1.5 @Deprecated()
+    public static void printMap(Object o, int loglevel, Map m) {
+        if (debug) {
+            if (o instanceof Class)
+                saveclass = (Class) o;
+            else
+                saveclass = o.getClass();
+            printMap(loglevel, m);
+        }
+    }
+
+    /**
+     * Log a Map
+     *
+     * @param c        The class doing the logging
+     * @param loglevel The level to log at (DEBUG, WARN, etc)
+     * @param m        The Map to print out
+     * @deprecated In Java 1.5 calling class is automatically identified, no need to pass it in.
+     */
+    //TODO: 1.5 @Deprecated()
+    public static void printMap(Class c, int loglevel, Map m) {
+        if (debug) {
+            saveclass = c;
+            printMap(loglevel, m);
+        }
+    }
+
+    /**
+     * Log a Map at DEBUG log level
+     *
+     * @param m The Map to print out
+     */
+    public static void printMap(Map m) {
+        printMap(DEBUG, m);
+    }
+
+    /**
+     * Log a Map
+     *
+     * @param loglevel The level to log at (DEBUG, WARN, etc)
+     * @param m        The Map to print out
+     */
+    public static void printMap(int loglevel, Map m) {
+        if (debug) {
+            String timestr = "";
+            String[] data = getTraceElements();
+            if (debugging(data[0], loglevel)) {
+                if (timing) {
+                    long now = System.currentTimeMillis();
+                    timestr = "{" + (now - last) + "} ";
+                    last = now;
+                }
+                Iterator i = m.keySet().iterator();
+                String[] lines = new String[m.size()];
+                int j = 0;
+                while (i.hasNext()) {
+                    Object key = i.next();
+                    lines[j++] = "\t\t- " + key + " => " + m.get(key);
+                }
+                _print(m.getClass(), loglevel, data[0] + "." + data[1] + "()" + data[2], timestr, "Map:", lines);
+            }
+        }
+    }
+
+    /**
+     * Enable or disable stack traces in Debuging throwables.
+     */
+    public static void setThrowableTraces(boolean ttrace) {
+        Debug.ttrace = ttrace;
+    }
+
+    /**
+     * Enable or disable timing in Debug messages.
+     */
+    public static void setTiming(boolean timing) {
+        Debug.timing = timing;
+    }
+
+    /**
+     * Enable or disable line numbers.
+     */
+    public static void setLineNos(boolean lines) {
+        Debug.lines = lines;
+    }
+
+    /**
+     * Enable or disable hexdumps.
+     */
+    public static void setHexDump(boolean hexdump) {
+        Debug.hexdump = hexdump;
+    }
+
+    /**
+     * Set the size of hexdumps.
+     * (Default: 36)
+     */
+    public static void setByteArrayCount(int count) {
+        Debug.balen = count;
+    }
+
+    /**
+     * Set the formatted width of hexdumps.
+     * (Default: 80 chars)
+     */
+    public static void setByteArrayWidth(int width) {
+        Debug.bawidth = width;
+    }
+
+    /**
+     * Add a filter command for a specific type.
+     * This command will be called with the output stream
+     * and the text to be sent. It should perform any
+     * changes necessary to the text and then print the
+     * result to the output stream.
+     */
+    public static void addFilterCommand(Class c, FilterCommand f)
+    //TODO 1.5: public static void addFilterCommand(Class<? extends Object> c, FilterCommand f)
+    {
+        filterMap.put(c, f);
+    }
+
+    private static void _print(Class c, int level, String loc, String extra, String message, String[] lines) {
+        //TODO 1.5: FilterCommand f = filterMap.get(c);
+        FilterCommand f = (FilterCommand) filterMap.get(c);
+        if (null == f) {
+            debugout.println("[" + loc + "] " + extra + message);
+            if (null != lines)
+                for (String s : lines)
+                    debugout.println(s);
+        } else
+            f.filter(debugout, level, loc, extra, message, lines);
+    }
+}
                diff --git a/federation/sssd/src/main/java/cx/ath/matthew/LibraryLoader.java b/federation/sssd/src/main/java/cx/ath/matthew/LibraryLoader.java
new file mode 100644
index 0000000..ffdf02d
--- /dev/null
+++ b/federation/sssd/src/main/java/cx/ath/matthew/LibraryLoader.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package cx.ath.matthew;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * @author <a href="mailto:bruno@abstractj.org">Bruno Oliveira</a>.
+ */
+public class LibraryLoader {
+
+    private static final Logger LOGGER = Logger.getLogger(LibraryLoader.class.getSimpleName());
+
+    private static final String[] PATHS = {"/usr/lib/", "/usr/lib64/", "/usr/local/lib/", "/opt/local/lib/"};
+    private static final String LIBRARY_NAME = "libunix_dbus_java";
+    private static final String VERSION = "0.0.8";
+    private static boolean loadSucceeded;
+
+    public static void load() {
+        for (String path : PATHS) {
+            try {
+                System.load(String.format("%s/%s.so.%s", path, LIBRARY_NAME, VERSION));
+                loadSucceeded = true;
+                break;
+            } catch (UnsatisfiedLinkError e) {
+                loadSucceeded = false;
+            }
+
+        }
+
+        if (!loadSucceeded) LOGGER.log(Level.WARNING, "libunix_dbus_java not found\n" +
+                "Please, make sure you have the package libunix-dbus-java installed.");
+    }
+}
                diff --git a/federation/sssd/src/main/java/cx/ath/matthew/unix/NotConnectedException.java b/federation/sssd/src/main/java/cx/ath/matthew/unix/NotConnectedException.java
new file mode 100644
index 0000000..836f5d6
--- /dev/null
+++ b/federation/sssd/src/main/java/cx/ath/matthew/unix/NotConnectedException.java
@@ -0,0 +1,35 @@
+/*
+ * Java Unix Sockets Library
+ *
+ * Copyright (c) Matthew Johnson 2004
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ * 
+ * To Contact the author, please email src@matthew.ath.cx
+ *
+ */
+package cx.ath.matthew.unix;
+
+import java.net.SocketException;
+
+public class NotConnectedException extends SocketException {
+    public NotConnectedException() {
+        super("The Socket is Not Connected");
+    }
+}
                diff --git a/federation/sssd/src/main/java/cx/ath/matthew/unix/UnixIOException.java b/federation/sssd/src/main/java/cx/ath/matthew/unix/UnixIOException.java
new file mode 100644
index 0000000..24fd20c
--- /dev/null
+++ b/federation/sssd/src/main/java/cx/ath/matthew/unix/UnixIOException.java
@@ -0,0 +1,43 @@
+/*
+ * Java Unix Sockets Library
+ *
+ * Copyright (c) Matthew Johnson 2004
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ * 
+ * To Contact the author, please email src@matthew.ath.cx
+ *
+ */
+package cx.ath.matthew.unix;
+
+import java.io.IOException;
+
+/**
+ * An IO Exception which occurred during UNIX Socket IO
+ */
+public class UnixIOException extends IOException {
+    private int no;
+    private String message;
+
+    public UnixIOException(int no, String message) {
+        super(message);
+        this.message = message;
+        this.no = no;
+    }
+}
                diff --git a/federation/sssd/src/main/java/cx/ath/matthew/unix/UnixSocket.java b/federation/sssd/src/main/java/cx/ath/matthew/unix/UnixSocket.java
new file mode 100644
index 0000000..8851637
--- /dev/null
+++ b/federation/sssd/src/main/java/cx/ath/matthew/unix/UnixSocket.java
@@ -0,0 +1,350 @@
+/*
+ * Java Unix Sockets Library
+ *
+ * Copyright (c) Matthew Johnson 2004
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ * 
+ * To Contact the author, please email src@matthew.ath.cx
+ *
+ */
+package cx.ath.matthew.unix;
+
+import cx.ath.matthew.LibraryLoader;
+import cx.ath.matthew.debug.Debug;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Represents a UnixSocket.
+ */
+public class UnixSocket {
+    static {
+        LibraryLoader.load();
+    }
+
+    private native void native_set_pass_cred(int sock, boolean passcred) throws IOException;
+
+    private native int native_connect(String address, boolean abs) throws IOException;
+
+    private native void native_close(int sock) throws IOException;
+
+    private native int native_getPID(int sock);
+
+    private native int native_getUID(int sock);
+
+    private native int native_getGID(int sock);
+
+    private native void native_send_creds(int sock, byte data) throws IOException;
+
+    private native byte native_recv_creds(int sock, int[] creds) throws IOException;
+
+    private UnixSocketAddress address = null;
+    private USOutputStream os = null;
+    private USInputStream is = null;
+    private boolean closed = false;
+    private boolean connected = false;
+    private boolean passcred = false;
+    private int sock = 0;
+    private boolean blocking = true;
+    private int uid = -1;
+    private int pid = -1;
+    private int gid = -1;
+
+    UnixSocket(int sock, UnixSocketAddress address) {
+        this.sock = sock;
+        this.address = address;
+        this.connected = true;
+        this.os = new USOutputStream(sock, this);
+        this.is = new USInputStream(sock, this);
+    }
+
+    /**
+     * Create an unconnected socket.
+     */
+    public UnixSocket() {
+    }
+
+    /**
+     * Create a socket connected to the given address.
+     *
+     * @param address The Unix Socket address to connect to
+     */
+    public UnixSocket(UnixSocketAddress address) throws IOException {
+        connect(address);
+    }
+
+    /**
+     * Create a socket connected to the given address.
+     *
+     * @param address The Unix Socket address to connect to
+     */
+    public UnixSocket(String address) throws IOException {
+        this(new UnixSocketAddress(address));
+    }
+
+    /**
+     * Connect the socket to this address.
+     *
+     * @param address The Unix Socket address to connect to
+     */
+    public void connect(UnixSocketAddress address) throws IOException {
+        if (connected) close();
+        this.sock = native_connect(address.path, address.abs);
+        this.os = new USOutputStream(this.sock, this);
+        this.is = new USInputStream(this.sock, this);
+        this.address = address;
+        this.connected = true;
+        this.closed = false;
+        this.is.setBlocking(blocking);
+    }
+
+    /**
+     * Connect the socket to this address.
+     *
+     * @param address The Unix Socket address to connect to
+     */
+    public void connect(String address) throws IOException {
+        connect(new UnixSocketAddress(address));
+    }
+
+    public void finalize() {
+        try {
+            close();
+        } catch (IOException IOe) {
+        }
+    }
+
+    /**
+     * Closes the connection.
+     */
+    public synchronized void close() throws IOException {
+        if (Debug.debug) Debug.print(Debug.INFO, "Closing socket");
+        native_close(sock);
+        sock = 0;
+        this.closed = true;
+        this.connected = false;
+        os = null;
+        is = null;
+    }
+
+    /**
+     * Returns an InputStream for reading from the socket.
+     *
+     * @return An InputStream connected to this socket.
+     */
+    public InputStream getInputStream() {
+        return is;
+    }
+
+    /**
+     * Returns an OutputStream for writing to the socket.
+     *
+     * @return An OutputStream connected to this socket.
+     */
+    public OutputStream getOutputStream() {
+        return os;
+    }
+
+    /**
+     * Returns the address this socket is connected to.
+     * Returns null if the socket is unconnected.
+     *
+     * @return The UnixSocketAddress the socket is connected to
+     */
+    public UnixSocketAddress getAddress() {
+        return address;
+    }
+
+    /**
+     * Send a single byte of data with credentials.
+     * (Works on BSDs)
+     *
+     * @param data The byte of data to send.
+     */
+    public void sendCredentialByte(byte data) throws IOException {
+        if (!connected) throw new NotConnectedException();
+        native_send_creds(sock, data);
+    }
+
+    /**
+     * Receive a single byte of data, with credentials.
+     * (Works on BSDs)
+     *
+     * @param data The byte of data to send.
+     * @see getPeerUID
+     * @see getPeerPID
+     * @see getPeerGID
+     */
+    public byte recvCredentialByte() throws IOException {
+        if (!connected) throw new NotConnectedException();
+        int[] creds = new int[]{-1, -1, -1};
+        byte data = native_recv_creds(sock, creds);
+        pid = creds[0];
+        uid = creds[1];
+        gid = creds[2];
+        return data;
+    }
+
+    /**
+     * Get the credential passing status.
+     * (only effective on linux)
+     *
+     * @return The current status of credential passing.
+     * @see setPassCred
+     */
+    public boolean getPassCred() {
+        return passcred;
+    }
+
+    /**
+     * Return the uid of the remote process.
+     * Some data must have been received on the socket to do this.
+     * Either setPassCred must be called on Linux first, or recvCredentialByte
+     * on BSD.
+     *
+     * @return the UID or -1 if it is not available
+     */
+    public int getPeerUID() {
+        if (-1 == uid)
+            uid = native_getUID(sock);
+        return uid;
+    }
+
+    /**
+     * Return the gid of the remote process.
+     * Some data must have been received on the socket to do this.
+     * Either setPassCred must be called on Linux first, or recvCredentialByte
+     * on BSD.
+     *
+     * @return the GID or -1 if it is not available
+     */
+    public int getPeerGID() {
+        if (-1 == gid)
+            gid = native_getGID(sock);
+        return gid;
+    }
+
+    /**
+     * Return the pid of the remote process.
+     * Some data must have been received on the socket to do this.
+     * Either setPassCred must be called on Linux first, or recvCredentialByte
+     * on BSD.
+     *
+     * @return the PID or -1 if it is not available
+     */
+    public int getPeerPID() {
+        if (-1 == pid)
+            pid = native_getPID(sock);
+        return pid;
+    }
+
+    /**
+     * Set the credential passing status.
+     * (Only does anything on linux, for other OS, you need
+     * to use send/recv credentials)
+     *
+     * @param enable Set to true for credentials to be passed.
+     */
+    public void setPassCred(boolean enable) throws IOException {
+        native_set_pass_cred(sock, enable);
+        passcred = enable;
+    }
+
+    /**
+     * Get the blocking mode.
+     *
+     * @return true if reads are blocking.
+     * @see setBlocking
+     */
+    public boolean getBlocking() {
+        return blocking;
+    }
+
+    /**
+     * Set the blocking mode.
+     *
+     * @param enable Set to false for non-blocking reads.
+     */
+    public void setBlocking(boolean enable) {
+        blocking = enable;
+        if (null != is) is.setBlocking(enable);
+    }
+
+    /**
+     * Check the socket status.
+     *
+     * @return true if closed.
+     */
+    public boolean isClosed() {
+        return closed;
+    }
+
+    /**
+     * Check the socket status.
+     *
+     * @return true if connected.
+     */
+    public boolean isConnected() {
+        return connected;
+    }
+
+    /**
+     * Check the socket status.
+     *
+     * @return true if the input stream has been shutdown
+     */
+    public boolean isInputShutdown() {
+        return is.isClosed();
+    }
+
+    /**
+     * Check the socket status.
+     *
+     * @return true if the output stream has been shutdown
+     */
+    public boolean isOutputShutdown() {
+        return os.isClosed();
+    }
+
+    /**
+     * Shuts down the input stream.
+     * Subsequent reads on the associated InputStream will fail.
+     */
+    public void shutdownInput() {
+        is.closed = true;
+    }
+
+    /**
+     * Shuts down the output stream.
+     * Subsequent writes to the associated OutputStream will fail.
+     */
+    public void shutdownOutput() {
+        os.closed = true;
+    }
+
+    /**
+     * Set timeout of read requests.
+     */
+    public void setSoTimeout(int timeout) {
+        is.setSoTimeout(timeout);
+    }
+}
                diff --git a/federation/sssd/src/main/java/cx/ath/matthew/unix/UnixSocketAddress.java b/federation/sssd/src/main/java/cx/ath/matthew/unix/UnixSocketAddress.java
new file mode 100644
index 0000000..0baba47
--- /dev/null
+++ b/federation/sssd/src/main/java/cx/ath/matthew/unix/UnixSocketAddress.java
@@ -0,0 +1,86 @@
+/*
+ * Java Unix Sockets Library
+ *
+ * Copyright (c) Matthew Johnson 2004
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ * 
+ * To Contact the author, please email src@matthew.ath.cx
+ *
+ */
+package cx.ath.matthew.unix;
+
+/**
+ * Represents an address for a Unix Socket
+ */
+public class UnixSocketAddress {
+    String path;
+    boolean abs;
+
+    /**
+     * Create the address.
+     *
+     * @param path The path to the Unix Socket.
+     * @param abs  True if this should be an abstract socket.
+     */
+    public UnixSocketAddress(String path, boolean abs) {
+        this.path = path;
+        this.abs = abs;
+    }
+
+    /**
+     * Create the address.
+     *
+     * @param path The path to the Unix Socket.
+     */
+    public UnixSocketAddress(String path) {
+        this.path = path;
+        this.abs = false;
+    }
+
+    /**
+     * Return the path.
+     */
+    public String getPath() {
+        return path;
+    }
+
+    /**
+     * Returns true if this an address for an abstract socket.
+     */
+    public boolean isAbstract() {
+        return abs;
+    }
+
+    /**
+     * Return the Address as a String.
+     */
+    public String toString() {
+        return "unix" + (abs ? ":abstract" : "") + ":path=" + path;
+    }
+
+    public boolean equals(Object o) {
+        if (!(o instanceof UnixSocketAddress)) return false;
+        return ((UnixSocketAddress) o).path.equals(this.path);
+    }
+
+    public int hashCode() {
+        return path.hashCode();
+    }
+}
                diff --git a/federation/sssd/src/main/java/cx/ath/matthew/unix/USInputStream.java b/federation/sssd/src/main/java/cx/ath/matthew/unix/USInputStream.java
new file mode 100644
index 0000000..eb143fe
--- /dev/null
+++ b/federation/sssd/src/main/java/cx/ath/matthew/unix/USInputStream.java
@@ -0,0 +1,94 @@
+/*
+ * Java Unix Sockets Library
+ *
+ * Copyright (c) Matthew Johnson 2004
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ * 
+ * To Contact the author, please email src@matthew.ath.cx
+ *
+ */
+package cx.ath.matthew.unix;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public class USInputStream extends InputStream {
+    public static final int MSG_DONTWAIT = 0x40;
+
+    private native int native_recv(int sock, byte[] b, int off, int len, int flags, int timeout) throws IOException;
+
+    private int sock;
+    boolean closed = false;
+    private byte[] onebuf = new byte[1];
+    private UnixSocket us;
+    private boolean blocking = true;
+    private int flags = 0;
+    private int timeout = 0;
+
+    public USInputStream(int sock, UnixSocket us) {
+        this.sock = sock;
+        this.us = us;
+    }
+
+    public void close() throws IOException {
+        closed = true;
+        us.close();
+    }
+
+    public boolean markSupported() {
+        return false;
+    }
+
+    public int read() throws IOException {
+        int rv = 0;
+        while (0 >= rv) rv = read(onebuf);
+        if (-1 == rv) return -1;
+        return 0 > onebuf[0] ? -onebuf[0] : onebuf[0];
+    }
+
+    public int read(byte[] b, int off, int len) throws IOException {
+        if (closed) throw new NotConnectedException();
+        int count = native_recv(sock, b, off, len, flags, timeout);
+      /* Yes, I really want to do this. Recv returns 0 for 'connection shut down'.
+       * read() returns -1 for 'end of stream.
+       * Recv returns -1 for 'EAGAIN' (all other errors cause an exception to be raised)
+       * whereas read() returns 0 for '0 bytes read', so yes, I really want to swap them here.
+       */
+        if (0 == count) return -1;
+        else if (-1 == count) return 0;
+        else return count;
+    }
+
+    public boolean isClosed() {
+        return closed;
+    }
+
+    public UnixSocket getSocket() {
+        return us;
+    }
+
+    public void setBlocking(boolean enable) {
+        flags = enable ? 0 : MSG_DONTWAIT;
+    }
+
+    public void setSoTimeout(int timeout) {
+        this.timeout = timeout;
+    }
+}
                diff --git a/federation/sssd/src/main/java/cx/ath/matthew/unix/USOutputStream.java b/federation/sssd/src/main/java/cx/ath/matthew/unix/USOutputStream.java
new file mode 100644
index 0000000..d8c85a7
--- /dev/null
+++ b/federation/sssd/src/main/java/cx/ath/matthew/unix/USOutputStream.java
@@ -0,0 +1,78 @@
+/*
+ * Java Unix Sockets Library
+ *
+ * Copyright (c) Matthew Johnson 2004
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ * 
+ * To Contact the author, please email src@matthew.ath.cx
+ *
+ */
+package cx.ath.matthew.unix;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class USOutputStream extends OutputStream {
+    private native int native_send(int sock, byte[] b, int off, int len) throws IOException;
+
+    private native int native_send(int sock, byte[][] b) throws IOException;
+
+    private int sock;
+    boolean closed = false;
+    private byte[] onebuf = new byte[1];
+    private UnixSocket us;
+
+    public USOutputStream(int sock, UnixSocket us) {
+        this.sock = sock;
+        this.us = us;
+    }
+
+    public void close() throws IOException {
+        closed = true;
+        us.close();
+    }
+
+    public void flush() {
+    } // no-op, we do not buffer
+
+    public void write(byte[][] b) throws IOException {
+        if (closed) throw new NotConnectedException();
+        native_send(sock, b);
+    }
+
+    public void write(byte[] b, int off, int len) throws IOException {
+        if (closed) throw new NotConnectedException();
+        native_send(sock, b, off, len);
+    }
+
+    public void write(int b) throws IOException {
+        onebuf[0] = (byte) (b % 0x7F);
+        if (1 == (b % 0x80)) onebuf[0] = (byte) -onebuf[0];
+        write(onebuf);
+    }
+
+    public boolean isClosed() {
+        return closed;
+    }
+
+    public UnixSocket getSocket() {
+        return us;
+    }
+}
                diff --git a/federation/sssd/src/main/java/cx/ath/matthew/utils/Hexdump.java b/federation/sssd/src/main/java/cx/ath/matthew/utils/Hexdump.java
new file mode 100644
index 0000000..63f3719
--- /dev/null
+++ b/federation/sssd/src/main/java/cx/ath/matthew/utils/Hexdump.java
@@ -0,0 +1,147 @@
+/*
+ * Java Hexdump Library
+ *
+ * Copyright (c) Matthew Johnson 2005
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ * 
+ * To Contact the author, please email src@matthew.ath.cx
+ *
+ */
+
+package cx.ath.matthew.utils;
+
+import java.io.PrintStream;
+
+public class Hexdump {
+    public static final char[] hexchars = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+
+    public static String toHex(byte[] buf) {
+        return toHex(buf, 0, buf.length);
+    }
+
+    public static String toHex(byte[] buf, int ofs, int len) {
+        StringBuffer sb = new StringBuffer();
+        int j = ofs + len;
+        for (int i = ofs; i < j; i++) {
+            if (i < buf.length) {
+                sb.append(hexchars[(buf[i] & 0xF0) >> 4]);
+                sb.append(hexchars[buf[i] & 0x0F]);
+                sb.append(' ');
+            } else {
+                sb.append(' ');
+                sb.append(' ');
+                sb.append(' ');
+            }
+        }
+        return sb.toString();
+    }
+
+    public static String toAscii(byte[] buf) {
+        return toAscii(buf, 0, buf.length);
+    }
+
+    public static String toAscii(byte[] buf, int ofs, int len) {
+        StringBuffer sb = new StringBuffer();
+        int j = ofs + len;
+        for (int i = ofs; i < j; i++) {
+            if (i < buf.length) {
+                if (20 <= buf[i] && 126 >= buf[i])
+                    sb.append((char) buf[i]);
+                else
+                    sb.append('.');
+            } else
+                sb.append(' ');
+        }
+        return sb.toString();
+    }
+
+    public static String format(byte[] buf) {
+        return format(buf, 80);
+    }
+
+    public static String format(byte[] buf, int width) {
+        int bs = (width - 8) / 4;
+        int i = 0;
+        StringBuffer sb = new StringBuffer();
+        do {
+            for (int j = 0; j < 6; j++) {
+                sb.append(hexchars[(i << (j * 4) & 0xF00000) >> 20]);
+            }
+            sb.append('\t');
+            sb.append(toHex(buf, i, bs));
+            sb.append(' ');
+            sb.append(toAscii(buf, i, bs));
+            sb.append('\n');
+            i += bs;
+        } while (i < buf.length);
+        return sb.toString();
+    }
+
+    public static void print(byte[] buf) {
+        print(buf, System.err);
+    }
+
+    public static void print(byte[] buf, int width) {
+        print(buf, width, System.err);
+    }
+
+    public static void print(byte[] buf, int width, PrintStream out) {
+        out.print(format(buf, width));
+    }
+
+    public static void print(byte[] buf, PrintStream out) {
+        out.print(format(buf));
+    }
+
+    /**
+     * Returns a string which can be written to a Java source file as part
+     * of a static initializer for a byte array.
+     * Returns data in the format 0xAB, 0xCD, ....
+     * use like:
+     * javafile.print("byte[] data = {")
+     * javafile.print(Hexdump.toByteArray(data));
+     * javafile.println("};");
+     */
+    public static String toByteArray(byte[] buf) {
+        return toByteArray(buf, 0, buf.length);
+    }
+
+    /**
+     * Returns a string which can be written to a Java source file as part
+     * of a static initializer for a byte array.
+     * Returns data in the format 0xAB, 0xCD, ....
+     * use like:
+     * javafile.print("byte[] data = {")
+     * javafile.print(Hexdump.toByteArray(data));
+     * javafile.println("};");
+     */
+    public static String toByteArray(byte[] buf, int ofs, int len) {
+        StringBuffer sb = new StringBuffer();
+        for (int i = ofs; i < len && i < buf.length; i++) {
+            sb.append('0');
+            sb.append('x');
+            sb.append(hexchars[(buf[i] & 0xF0) >> 4]);
+            sb.append(hexchars[buf[i] & 0x0F]);
+            if ((i + 1) < len && (i + 1) < buf.length)
+                sb.append(',');
+        }
+        return sb.toString();
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/DBus.java b/federation/sssd/src/main/java/org/freedesktop/DBus.java
new file mode 100644
index 0000000..1aa180a
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/DBus.java
@@ -0,0 +1,530 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop;
+
+import org.freedesktop.dbus.DBusInterface;
+import org.freedesktop.dbus.DBusSignal;
+import org.freedesktop.dbus.Position;
+import org.freedesktop.dbus.Struct;
+import org.freedesktop.dbus.Tuple;
+import org.freedesktop.dbus.UInt16;
+import org.freedesktop.dbus.UInt32;
+import org.freedesktop.dbus.UInt64;
+import org.freedesktop.dbus.Variant;
+import org.freedesktop.dbus.exceptions.DBusException;
+import org.freedesktop.dbus.exceptions.DBusExecutionException;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.List;
+import java.util.Map;
+
+public interface DBus extends DBusInterface {
+    public static final int DBUS_NAME_FLAG_ALLOW_REPLACEMENT = 0x01;
+    public static final int DBUS_NAME_FLAG_REPLACE_EXISTING = 0x02;
+    public static final int DBUS_NAME_FLAG_DO_NOT_QUEUE = 0x04;
+    public static final int DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER = 1;
+    public static final int DBUS_REQUEST_NAME_REPLY_IN_QUEUE = 2;
+    public static final int DBUS_REQUEST_NAME_REPLY_EXISTS = 3;
+    public static final int DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER = 4;
+    public static final int DBUS_RELEASE_NAME_REPLY_RELEASED = 1;
+    public static final int DBUS_RELEASE_NAME_REPLY_NON_EXISTANT = 2;
+    public static final int DBUS_RELEASE_NAME_REPLY_NOT_OWNER = 3;
+    public static final int DBUS_START_REPLY_SUCCESS = 1;
+    public static final int DBUS_START_REPLY_ALREADY_RUNNING = 2;
+
+    /**
+     * All DBus Applications should respond to the Ping method on this interface
+     */
+    public interface Peer extends DBusInterface {
+        public void Ping();
+    }
+
+    /**
+     * Objects can provide introspection data via this interface and method.
+     * See the <a href="http://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format">Introspection Format</a>.
+     */
+    public interface Introspectable extends DBusInterface {
+        /**
+         * @return The XML introspection data for this object
+         */
+        public String Introspect();
+    }
+
+    /**
+     * A standard properties interface.
+     */
+    public interface Properties extends DBusInterface {
+        /**
+         * Get the value for the given property.
+         *
+         * @param interface_name The interface this property is associated with.
+         * @param property_name  The name of the property.
+         * @return The value of the property (may be any valid DBus type).
+         */
+        public <A> A Get(String interface_name, String property_name);
+
+        /**
+         * Set the value for the given property.
+         *
+         * @param interface_name The interface this property is associated with.
+         * @param property_name  The name of the property.
+         * @param value          The new value of the property (may be any valid DBus type).
+         */
+        public <A> void Set(String interface_name, String property_name, A value);
+
+        /**
+         * Get all properties and values.
+         *
+         * @param interface_name The interface the properties is associated with.
+         * @return The properties mapped to their values.
+         */
+        public Map<String, Variant> GetAll(String interface_name);
+    }
+
+    /**
+     * Messages generated locally in the application.
+     */
+    public interface Local extends DBusInterface {
+        public class Disconnected extends DBusSignal {
+            public Disconnected(String path) throws DBusException {
+                super(path);
+            }
+        }
+    }
+
+    /**
+     * Initial message to register ourselves on the Bus.
+     *
+     * @return The unique name of this connection to the Bus.
+     */
+    public String Hello();
+
+    /**
+     * Lists all connected names on the Bus.
+     *
+     * @return An array of all connected names.
+     */
+    public String[] ListNames();
+
+    /**
+     * Determine if a name has an owner.
+     *
+     * @param name The name to query.
+     * @return true if the name has an owner.
+     */
+    public boolean NameHasOwner(String name);
+
+    /**
+     * Get the connection unique name that owns the given name.
+     *
+     * @param name The name to query.
+     * @return The connection which owns the name.
+     */
+    public String GetNameOwner(String name);
+
+    /**
+     * Get the Unix UID that owns a connection name.
+     *
+     * @param connection_name The connection name.
+     * @return The Unix UID that owns it.
+     */
+    public UInt32 GetConnectionUnixUser(String connection_name);
+
+    /**
+     * Start a service. If the given service is not provided
+     * by any application, it will be started according to the .service file
+     * for that service.
+     *
+     * @param name  The service name to start.
+     * @param flags Unused.
+     * @return DBUS_START_REPLY constants.
+     */
+    public UInt32 StartServiceByName(String name, UInt32 flags);
+
+    /**
+     * Request a name on the bus.
+     *
+     * @param name  The name to request.
+     * @param flags DBUS_NAME flags.
+     * @return DBUS_REQUEST_NAME_REPLY constants.
+     */
+    public UInt32 RequestName(String name, UInt32 flags);
+
+    /**
+     * Release a name on the bus.
+     *
+     * @param name The name to release.
+     * @return DBUS_RELEASE_NAME_REPLY constants.
+     */
+    public UInt32 ReleaseName(String name);
+
+    /**
+     * Add a match rule.
+     * Will cause you to receive messages that aren't directed to you which
+     * match this rule.
+     *
+     * @param matchrule The Match rule as a string. Format Undocumented.
+     */
+    public void AddMatch(String matchrule) throws Error.MatchRuleInvalid;
+
+    /**
+     * Remove a match rule.
+     * Will cause you to stop receiving messages that aren't directed to you which
+     * match this rule.
+     *
+     * @param matchrule The Match rule as a string. Format Undocumented.
+     */
+    public void RemoveMatch(String matchrule) throws Error.MatchRuleInvalid;
+
+    /**
+     * List the connections currently queued for a name.
+     *
+     * @param name The name to query
+     * @return A list of unique connection IDs.
+     */
+    public String[] ListQueuedOwners(String name);
+
+    /**
+     * Returns the proccess ID associated with a connection.
+     *
+     * @param connection_name The name of the connection
+     * @return The PID of the connection.
+     */
+    public UInt32 GetConnectionUnixProcessID(String connection_name);
+
+    /**
+     * Does something undocumented.
+     */
+    public Byte[] GetConnectionSELinuxSecurityContext(String a);
+
+    /**
+     * Does something undocumented.
+     */
+    public void ReloadConfig();
+
+    /**
+     * Signal sent when the owner of a name changes
+     */
+    public class NameOwnerChanged extends DBusSignal {
+        public final String name;
+        public final String old_owner;
+        public final String new_owner;
+
+        public NameOwnerChanged(String path, String name, String old_owner, String new_owner) throws DBusException {
+            super(path, new Object[]{name, old_owner, new_owner});
+            this.name = name;
+            this.old_owner = old_owner;
+            this.new_owner = new_owner;
+        }
+    }
+
+    /**
+     * Signal sent to a connection when it loses a name
+     */
+    public class NameLost extends DBusSignal {
+        public final String name;
+
+        public NameLost(String path, String name) throws DBusException {
+            super(path, name);
+            this.name = name;
+        }
+    }
+
+    /**
+     * Signal sent to a connection when it aquires a name
+     */
+    public class NameAcquired extends DBusSignal {
+        public final String name;
+
+        public NameAcquired(String path, String name) throws DBusException {
+            super(path, name);
+            this.name = name;
+        }
+    }
+
+    /**
+     * Contains standard errors that can be thrown from methods.
+     */
+    public interface Error {
+        /**
+         * Thrown if the method called was unknown on the remote object
+         */
+        @SuppressWarnings("serial")
+        public class UnknownMethod extends DBusExecutionException {
+            public UnknownMethod(String message) {
+                super(message);
+            }
+        }
+
+        /**
+         * Thrown if the object was unknown on a remote connection
+         */
+        @SuppressWarnings("serial")
+        public class UnknownObject extends DBusExecutionException {
+            public UnknownObject(String message) {
+                super(message);
+            }
+        }
+
+        /**
+         * Thrown if the requested service was not available
+         */
+        @SuppressWarnings("serial")
+        public class ServiceUnknown extends DBusExecutionException {
+            public ServiceUnknown(String message) {
+                super(message);
+            }
+        }
+
+        /**
+         * Thrown if the match rule is invalid
+         */
+        @SuppressWarnings("serial")
+        public class MatchRuleInvalid extends DBusExecutionException {
+            public MatchRuleInvalid(String message) {
+                super(message);
+            }
+        }
+
+        /**
+         * Thrown if there is no reply to a method call
+         */
+        @SuppressWarnings("serial")
+        public class NoReply extends DBusExecutionException {
+            public NoReply(String message) {
+                super(message);
+            }
+        }
+
+        /**
+         * Thrown if a message is denied due to a security policy
+         */
+        @SuppressWarnings("serial")
+        public class AccessDenied extends DBusExecutionException {
+            public AccessDenied(String message) {
+                super(message);
+            }
+        }
+    }
+
+    /**
+     * Description of the interface or method, returned in the introspection data
+     */
+    @Retention(RetentionPolicy.RUNTIME)
+    public @interface Description {
+        String value();
+    }
+
+    /**
+     * Indicates that a DBus interface or method is deprecated
+     */
+    @Retention(RetentionPolicy.RUNTIME)
+    public @interface Deprecated {
+    }
+
+    /**
+     * Contains method-specific annotations
+     */
+    public interface Method {
+        /**
+         * Methods annotated with this do not send a reply
+         */
+        @Target(ElementType.METHOD)
+        @Retention(RetentionPolicy.RUNTIME)
+        public @interface NoReply {
+        }
+
+        /**
+         * Give an error that the method can return
+         */
+        @Target(ElementType.METHOD)
+        @Retention(RetentionPolicy.RUNTIME)
+        public @interface Error {
+            String value();
+        }
+    }
+
+    /**
+     * Contains GLib-specific annotations
+     */
+    public interface GLib {
+        /**
+         * Define a C symbol to map to this method. Used by GLib only
+         */
+        @Target(ElementType.METHOD)
+        @Retention(RetentionPolicy.RUNTIME)
+        public @interface CSymbol {
+            String value();
+        }
+    }
+
+    /**
+     * Contains Binding-test interfaces
+     */
+    public interface Binding {
+        public interface SingleTests extends DBusInterface {
+            @Description("Returns the sum of the values in the input list")
+            public UInt32 Sum(byte[] a);
+        }
+
+        public interface TestClient extends DBusInterface {
+            @Description("when the trigger signal is received, this method should be called on the sending process/object.")
+            public void Response(UInt16 a, double b);
+
+            @Description("Causes a callback")
+            public static class Trigger extends DBusSignal {
+                public final UInt16 a;
+                public final double b;
+
+                public Trigger(String path, UInt16 a, double b) throws DBusException {
+                    super(path, a, b);
+                    this.a = a;
+                    this.b = b;
+                }
+            }
+
+        }
+
+        public interface Tests extends DBusInterface {
+            @Description("Returns whatever it is passed")
+            public <T> Variant<T> Identity(Variant<T> input);
+
+            @Description("Returns whatever it is passed")
+            public byte IdentityByte(byte input);
+
+            @Description("Returns whatever it is passed")
+            public boolean IdentityBool(boolean input);
+
+            @Description("Returns whatever it is passed")
+            public short IdentityInt16(short input);
+
+            @Description("Returns whatever it is passed")
+            public UInt16 IdentityUInt16(UInt16 input);
+
+            @Description("Returns whatever it is passed")
+            public int IdentityInt32(int input);
+
+            @Description("Returns whatever it is passed")
+            public UInt32 IdentityUInt32(UInt32 input);
+
+            @Description("Returns whatever it is passed")
+            public long IdentityInt64(long input);
+
+            @Description("Returns whatever it is passed")
+            public UInt64 IdentityUInt64(UInt64 input);
+
+            @Description("Returns whatever it is passed")
+            public double IdentityDouble(double input);
+
+            @Description("Returns whatever it is passed")
+            public String IdentityString(String input);
+
+            @Description("Returns whatever it is passed")
+            public <T> Variant<T>[] IdentityArray(Variant<T>[] input);
+
+            @Description("Returns whatever it is passed")
+            public byte[] IdentityByteArray(byte[] input);
+
+            @Description("Returns whatever it is passed")
+            public boolean[] IdentityBoolArray(boolean[] input);
+
+            @Description("Returns whatever it is passed")
+            public short[] IdentityInt16Array(short[] input);
+
+            @Description("Returns whatever it is passed")
+            public UInt16[] IdentityUInt16Array(UInt16[] input);
+
+            @Description("Returns whatever it is passed")
+            public int[] IdentityInt32Array(int[] input);
+
+            @Description("Returns whatever it is passed")
+            public UInt32[] IdentityUInt32Array(UInt32[] input);
+
+            @Description("Returns whatever it is passed")
+            public long[] IdentityInt64Array(long[] input);
+
+            @Description("Returns whatever it is passed")
+            public UInt64[] IdentityUInt64Array(UInt64[] input);
+
+            @Description("Returns whatever it is passed")
+            public double[] IdentityDoubleArray(double[] input);
+
+            @Description("Returns whatever it is passed")
+            public String[] IdentityStringArray(String[] input);
+
+            @Description("Returns the sum of the values in the input list")
+            public long Sum(int[] a);
+
+            @Description("Given a map of A => B, should return a map of B => a list of all the As which mapped to B")
+            public Map<String, List<String>> InvertMapping(Map<String, String> a);
+
+            @Description("This method returns the contents of a struct as separate values")
+            public Triplet<String, UInt32, Short> DeStruct(TestStruct a);
+
+            @Description("Given any compound type as a variant, return all the primitive types recursively contained within as an array of variants")
+            public List<Variant<Object>> Primitize(Variant<Object> a);
+
+            @Description("inverts it's input")
+            public boolean Invert(boolean a);
+
+            @Description("triggers sending of a signal from the supplied object with the given parameter")
+            public void Trigger(String a, UInt64 b);
+
+            @Description("Causes the server to exit")
+            public void Exit();
+        }
+
+        public interface TestSignals extends DBusInterface {
+            @Description("Sent in response to a method call")
+            public static class Triggered extends DBusSignal {
+                public final UInt64 a;
+
+                public Triggered(String path, UInt64 a) throws DBusException {
+                    super(path, a);
+                    this.a = a;
+                }
+            }
+        }
+
+        public final class Triplet<A, B, C> extends Tuple {
+            @Position(0)
+            public final A a;
+            @Position(1)
+            public final B b;
+            @Position(2)
+            public final C c;
+
+            public Triplet(A a, B b, C c) {
+                this.a = a;
+                this.b = b;
+                this.c = c;
+            }
+        }
+
+        public final class TestStruct extends Struct {
+            @Position(0)
+            public final String a;
+            @Position(1)
+            public final UInt32 b;
+            @Position(2)
+            public final Short c;
+
+            public TestStruct(String a, UInt32 b, Short c) {
+                this.a = a;
+                this.b = b;
+                this.c = c;
+            }
+        }
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/AbstractConnection.java b/federation/sssd/src/main/java/org/freedesktop/dbus/AbstractConnection.java
new file mode 100644
index 0000000..d1d7f51
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/AbstractConnection.java
@@ -0,0 +1,1059 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import cx.ath.matthew.debug.Debug;
+import org.freedesktop.DBus;
+import org.freedesktop.dbus.exceptions.DBusException;
+import org.freedesktop.dbus.exceptions.DBusExecutionException;
+import org.freedesktop.dbus.exceptions.FatalDBusException;
+import org.freedesktop.dbus.exceptions.FatalException;
+import org.freedesktop.dbus.exceptions.NotConnected;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.text.MessageFormat;
+import java.text.ParseException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Vector;
+import java.util.regex.Pattern;
+
+import static org.freedesktop.dbus.Gettext.getString;
+
+
+/**
+ * Handles a connection to DBus.
+ */
+public abstract class AbstractConnection {
+    protected class FallbackContainer {
+        private Map<String[], ExportedObject> fallbacks = new HashMap<String[], ExportedObject>();
+
+        public synchronized void add(String path, ExportedObject eo) {
+            if (Debug.debug) Debug.print(Debug.DEBUG, "Adding fallback on " + path + " of " + eo);
+            fallbacks.put(path.split("/"), eo);
+        }
+
+        public synchronized void remove(String path) {
+            if (Debug.debug) Debug.print(Debug.DEBUG, "Removing fallback on " + path);
+            fallbacks.remove(path.split("/"));
+        }
+
+        public synchronized ExportedObject get(String path) {
+            int best = 0;
+            int i = 0;
+            ExportedObject bestobject = null;
+            String[] pathel = path.split("/");
+            for (String[] fbpath : fallbacks.keySet()) {
+                if (Debug.debug)
+                    Debug.print(Debug.VERBOSE, "Trying fallback path " + Arrays.deepToString(fbpath) + " to match " + Arrays.deepToString(pathel));
+                for (i = 0; i < pathel.length && i < fbpath.length; i++)
+                    if (!pathel[i].equals(fbpath[i])) break;
+                if (i > 0 && i == fbpath.length && i > best)
+                    bestobject = fallbacks.get(fbpath);
+                if (Debug.debug) Debug.print(Debug.VERBOSE, "Matches " + i + " bestobject now " + bestobject);
+            }
+            if (Debug.debug) Debug.print(Debug.DEBUG, "Found fallback for " + path + " of " + bestobject);
+            return bestobject;
+        }
+    }
+
+    protected class _thread extends Thread {
+        public _thread() {
+            setName("DBusConnection");
+        }
+
+        public void run() {
+            try {
+                Message m = null;
+                while (_run) {
+                    m = null;
+
+                    // read from the wire
+                    try {
+                        // this blocks on outgoing being non-empty or a message being available.
+                        m = readIncoming();
+                        if (m != null) {
+                            if (Debug.debug) Debug.print(Debug.VERBOSE, "Got Incoming Message: " + m);
+                            synchronized (this) {
+                                notifyAll();
+                            }
+
+                            if (m instanceof DBusSignal)
+                                handleMessage((DBusSignal) m);
+                            else if (m instanceof MethodCall)
+                                handleMessage((MethodCall) m);
+                            else if (m instanceof MethodReturn)
+                                handleMessage((MethodReturn) m);
+                            else if (m instanceof Error)
+                                handleMessage((Error) m);
+
+                            m = null;
+                        }
+                    } catch (Exception e) {
+                        if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
+                        if (e instanceof FatalException) {
+                            disconnect();
+                        }
+                    }
+
+                }
+                synchronized (this) {
+                    notifyAll();
+                }
+            } catch (Exception e) {
+                if (Debug.debug && EXCEPTION_DEBUG) Debug.print(Debug.ERR, e);
+            }
+        }
+    }
+
+    private class _globalhandler implements org.freedesktop.DBus.Peer, org.freedesktop.DBus.Introspectable {
+        private String objectpath;
+
+        public _globalhandler() {
+            this.objectpath = null;
+        }
+
+        public _globalhandler(String objectpath) {
+            this.objectpath = objectpath;
+        }
+
+        public boolean isRemote() {
+            return false;
+        }
+
+        public void Ping() {
+            return;
+        }
+
+        public String Introspect() {
+            String intro = objectTree.Introspect(objectpath);
+            if (null == intro) {
+                ExportedObject eo = fallbackcontainer.get(objectpath);
+                if (null != eo) intro = eo.introspectiondata;
+            }
+            if (null == intro)
+                throw new DBus.Error.UnknownObject("Introspecting on non-existant object");
+            else return
+                    "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" " +
+                            "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n" + intro;
+        }
+    }
+
+    protected class _workerthread extends Thread {
+        private boolean _run = true;
+
+        public void halt() {
+            _run = false;
+        }
+
+        public void run() {
+            while (_run) {
+                Runnable r = null;
+                synchronized (runnables) {
+                    while (runnables.size() == 0 && _run)
+                        try {
+                            runnables.wait();
+                        } catch (InterruptedException Ie) {
+                        }
+                    if (runnables.size() > 0)
+                        r = runnables.removeFirst();
+                }
+                if (null != r) r.run();
+            }
+        }
+    }
+
+    private class _sender extends Thread {
+        public _sender() {
+            setName("Sender");
+        }
+
+        public void run() {
+            Message m = null;
+
+            if (Debug.debug) Debug.print(Debug.INFO, "Monitoring outbound queue");
+            // block on the outbound queue and send from it
+            while (_run) {
+                if (null != outgoing) synchronized (outgoing) {
+                    if (Debug.debug) Debug.print(Debug.VERBOSE, "Blocking");
+                    while (outgoing.size() == 0 && _run)
+                        try {
+                            outgoing.wait();
+                        } catch (InterruptedException Ie) {
+                        }
+                    if (Debug.debug) Debug.print(Debug.VERBOSE, "Notified");
+                    if (outgoing.size() > 0)
+                        m = outgoing.remove();
+                    if (Debug.debug) Debug.print(Debug.DEBUG, "Got message: " + m);
+                }
+                if (null != m)
+                    sendMessage(m);
+                m = null;
+            }
+
+            if (Debug.debug) Debug.print(Debug.INFO, "Flushing outbound queue and quitting");
+            // flush the outbound queue before disconnect.
+            if (null != outgoing) do {
+                EfficientQueue ogq = outgoing;
+                synchronized (ogq) {
+                    outgoing = null;
+                }
+                if (!ogq.isEmpty())
+                    m = ogq.remove();
+                else m = null;
+                sendMessage(m);
+            } while (null != m);
+
+            // close the underlying streams
+        }
+    }
+
+    /**
+     * Timeout in us on checking the BUS for incoming messages and sending outgoing messages
+     */
+    protected static final int TIMEOUT = 100000;
+    /**
+     * Initial size of the pending calls map
+     */
+    private static final int PENDING_MAP_INITIAL_SIZE = 10;
+    static final String BUSNAME_REGEX = "^[-_a-zA-Z][-_a-zA-Z0-9]*(\\.[-_a-zA-Z][-_a-zA-Z0-9]*)*$";
+    static final String CONNID_REGEX = "^:[0-9]*\\.[0-9]*$";
+    static final String OBJECT_REGEX = "^/([-_a-zA-Z0-9]+(/[-_a-zA-Z0-9]+)*)?$";
+    static final byte THREADCOUNT = 4;
+    static final int MAX_ARRAY_LENGTH = 67108864;
+    static final int MAX_NAME_LENGTH = 255;
+    protected Map<String, ExportedObject> exportedObjects;
+    private ObjectTree objectTree;
+    private _globalhandler _globalhandlerreference;
+    protected Map<DBusInterface, RemoteObject> importedObjects;
+    protected Map<SignalTuple, Vector<DBusSigHandler<? extends DBusSignal>>> handledSignals;
+    protected EfficientMap pendingCalls;
+    protected Map<MethodCall, CallbackHandler<? extends Object>> pendingCallbacks;
+    protected Map<MethodCall, DBusAsyncReply<? extends Object>> pendingCallbackReplys;
+    protected LinkedList<Runnable> runnables;
+    protected LinkedList<_workerthread> workers;
+    protected FallbackContainer fallbackcontainer;
+    protected boolean _run;
+    EfficientQueue outgoing;
+    LinkedList<Error> pendingErrors;
+    private static final Map<Thread, DBusCallInfo> infomap = new HashMap<Thread, DBusCallInfo>();
+    protected _thread thread;
+    protected _sender sender;
+    protected Transport transport;
+    protected String addr;
+    protected boolean weakreferences = false;
+    static final Pattern dollar_pattern = Pattern.compile("[$]");
+    public static final boolean EXCEPTION_DEBUG;
+    static final boolean FLOAT_SUPPORT;
+    protected boolean connected = false;
+
+    static {
+        FLOAT_SUPPORT = (null != System.getenv("DBUS_JAVA_FLOATS"));
+        EXCEPTION_DEBUG = (null != System.getenv("DBUS_JAVA_EXCEPTION_DEBUG"));
+        if (EXCEPTION_DEBUG) {
+            Debug.print("Debugging of internal exceptions enabled");
+            Debug.setThrowableTraces(true);
+        }
+        if (Debug.debug) {
+            File f = new File("debug.conf");
+            if (f.exists()) {
+                Debug.print("Loading debug config file: " + f);
+                try {
+                    Debug.loadConfig(f);
+                } catch (IOException IOe) {
+                }
+            } else {
+                Properties p = new Properties();
+                p.setProperty("ALL", "INFO");
+                Debug.print("debug config file " + f + " does not exist, not loading.");
+            }
+            Debug.setHexDump(true);
+        }
+    }
+
+    protected AbstractConnection(String address) throws DBusException {
+        exportedObjects = new HashMap<String, ExportedObject>();
+        importedObjects = new HashMap<DBusInterface, RemoteObject>();
+        _globalhandlerreference = new _globalhandler();
+        synchronized (exportedObjects) {
+            exportedObjects.put(null, new ExportedObject(_globalhandlerreference, weakreferences));
+        }
+        handledSignals = new HashMap<SignalTuple, Vector<DBusSigHandler<? extends DBusSignal>>>();
+        pendingCalls = new EfficientMap(PENDING_MAP_INITIAL_SIZE);
+        outgoing = new EfficientQueue(PENDING_MAP_INITIAL_SIZE);
+        pendingCallbacks = new HashMap<MethodCall, CallbackHandler<? extends Object>>();
+        pendingCallbackReplys = new HashMap<MethodCall, DBusAsyncReply<? extends Object>>();
+        pendingErrors = new LinkedList<Error>();
+        runnables = new LinkedList<Runnable>();
+        workers = new LinkedList<_workerthread>();
+        objectTree = new ObjectTree();
+        fallbackcontainer = new FallbackContainer();
+        synchronized (workers) {
+            for (int i = 0; i < THREADCOUNT; i++) {
+                _workerthread t = new _workerthread();
+                t.start();
+                workers.add(t);
+            }
+        }
+        _run = true;
+        addr = address;
+    }
+
+    protected void listen() {
+        // start listening
+        thread = new _thread();
+        thread.start();
+        sender = new _sender();
+        sender.start();
+    }
+
+    /**
+     * Change the number of worker threads to receive method calls and handle signals.
+     * Default is 4 threads
+     *
+     * @param newcount The new number of worker Threads to use.
+     */
+    public void changeThreadCount(byte newcount) {
+        synchronized (workers) {
+            if (workers.size() > newcount) {
+                int n = workers.size() - newcount;
+                for (int i = 0; i < n; i++) {
+                    _workerthread t = workers.removeFirst();
+                    t.halt();
+                }
+            } else if (workers.size() < newcount) {
+                int n = newcount - workers.size();
+                for (int i = 0; i < n; i++) {
+                    _workerthread t = new _workerthread();
+                    t.start();
+                    workers.add(t);
+                }
+            }
+        }
+    }
+
+    private void addRunnable(Runnable r) {
+        synchronized (runnables) {
+            runnables.add(r);
+            runnables.notifyAll();
+        }
+    }
+
+    String getExportedObject(DBusInterface i) throws DBusException {
+        synchronized (exportedObjects) {
+            for (String s : exportedObjects.keySet())
+                if (i.equals(exportedObjects.get(s).object.get()))
+                    return s;
+        }
+
+        String s = importedObjects.get(i).objectpath;
+        if (null != s) return s;
+
+        throw new DBusException("Not an object exported or imported by this connection");
+    }
+
+    abstract DBusInterface getExportedObject(String source, String path) throws DBusException;
+
+    /**
+     * Returns a structure with information on the current method call.
+     *
+     * @return the DBusCallInfo for this method call, or null if we are not in a method call.
+     */
+    public static DBusCallInfo getCallInfo() {
+        DBusCallInfo info;
+        synchronized (infomap) {
+            info = infomap.get(Thread.currentThread());
+        }
+        return info;
+    }
+
+    /**
+     * If set to true the bus will not hold a strong reference to exported objects.
+     * If they go out of scope they will automatically be unexported from the bus.
+     * The default is to hold a strong reference, which means objects must be
+     * explicitly unexported before they will be garbage collected.
+     */
+    public void setWeakReferences(boolean weakreferences) {
+        this.weakreferences = weakreferences;
+    }
+
+    /**
+     * Export an object so that its methods can be called on DBus.
+     *
+     * @param objectpath The path to the object we are exposing. MUST be in slash-notation, like "/org/freedesktop/Local",
+     *                   and SHOULD end with a capitalised term. Only one object may be exposed on each path at any one time, but an object
+     *                   may be exposed on several paths at once.
+     * @param object     The object to export.
+     * @throws DBusException If the objectpath is already exporting an object.
+     *                       or if objectpath is incorrectly formatted,
+     */
+    public void exportObject(String objectpath, DBusInterface object) throws DBusException {
+        if (null == objectpath || "".equals(objectpath))
+            throw new DBusException(getString("missingObjectPath"));
+        if (!objectpath.matches(OBJECT_REGEX) || objectpath.length() > MAX_NAME_LENGTH)
+            throw new DBusException(getString("invalidObjectPath") + objectpath);
+        synchronized (exportedObjects) {
+            if (null != exportedObjects.get(objectpath))
+                throw new DBusException(getString("objectAlreadyExported"));
+            ExportedObject eo = new ExportedObject(object, weakreferences);
+            exportedObjects.put(objectpath, eo);
+            objectTree.add(objectpath, eo, eo.introspectiondata);
+        }
+    }
+
+    /**
+     * Export an object as a fallback object.
+     * This object will have it's methods invoked for all paths starting
+     * with this object path.
+     *
+     * @param objectprefix The path below which the fallback handles calls.
+     *                     MUST be in slash-notation, like "/org/freedesktop/Local",
+     * @param object       The object to export.
+     * @throws DBusException If the objectpath is incorrectly formatted,
+     */
+    public void addFallback(String objectprefix, DBusInterface object) throws DBusException {
+        if (null == objectprefix || "".equals(objectprefix))
+            throw new DBusException(getString("missingObjectPath"));
+        if (!objectprefix.matches(OBJECT_REGEX) || objectprefix.length() > MAX_NAME_LENGTH)
+            throw new DBusException(getString("invalidObjectPath") + objectprefix);
+        ExportedObject eo = new ExportedObject(object, weakreferences);
+        fallbackcontainer.add(objectprefix, eo);
+    }
+
+    /**
+     * Remove a fallback
+     *
+     * @param objectprefix The prefix to remove the fallback for.
+     */
+    public void removeFallback(String objectprefix) {
+        fallbackcontainer.remove(objectprefix);
+    }
+
+    /**
+     * Stop Exporting an object
+     *
+     * @param objectpath The objectpath to stop exporting.
+     */
+    public void unExportObject(String objectpath) {
+        synchronized (exportedObjects) {
+            exportedObjects.remove(objectpath);
+            objectTree.remove(objectpath);
+        }
+    }
+    /**
+     * Return a reference to a remote object.
+     * This method will resolve the well known name (if given) to a unique bus name when you call it.
+     * This means that if a well known name is released by one process and acquired by another calls to
+     * objects gained from this method will continue to operate on the original process.
+     * @param busname The bus name to connect to. Usually a well known bus name in dot-notation (such as "org.freedesktop.local")
+     * or may be a DBus address such as ":1-16".
+     * @param objectpath The path on which the process is exporting the object.$
+     * @param type The interface they are exporting it on. This type must have the same full class name and exposed method signatures
+     * as the interface the remote object is exporting.
+     * @return A reference to a remote object.
+     * @throws ClassCastException If type is not a sub-type of DBusInterface
+     * @throws DBusException If busname or objectpath are incorrectly formatted or type is not in a package.
+     */
+    /**
+     * Send a signal.
+     *
+     * @param signal The signal to send.
+     */
+    public void sendSignal(DBusSignal signal) {
+        queueOutgoing(signal);
+    }
+
+    void queueOutgoing(Message m) {
+        synchronized (outgoing) {
+            if (null == outgoing) return;
+            outgoing.add(m);
+            if (Debug.debug) Debug.print(Debug.DEBUG, "Notifying outgoing thread");
+            outgoing.notifyAll();
+        }
+    }
+
+    /**
+     * Remove a Signal Handler.
+     * Stops listening for this signal.
+     *
+     * @param type The signal to watch for.
+     * @throws DBusException      If listening for the signal on the bus failed.
+     * @throws ClassCastException If type is not a sub-type of DBusSignal.
+     */
+    public <T extends DBusSignal> void removeSigHandler(Class<T> type, DBusSigHandler<T> handler) throws DBusException {
+        if (!DBusSignal.class.isAssignableFrom(type)) throw new ClassCastException(getString("notDBusSignal"));
+        removeSigHandler(new DBusMatchRule(type), handler);
+    }
+
+    /**
+     * Remove a Signal Handler.
+     * Stops listening for this signal.
+     *
+     * @param type   The signal to watch for.
+     * @param object The object emitting the signal.
+     * @throws DBusException      If listening for the signal on the bus failed.
+     * @throws ClassCastException If type is not a sub-type of DBusSignal.
+     */
+    public <T extends DBusSignal> void removeSigHandler(Class<T> type, DBusInterface object, DBusSigHandler<T> handler) throws DBusException {
+        if (!DBusSignal.class.isAssignableFrom(type)) throw new ClassCastException(getString("notDBusSignal"));
+        String objectpath = importedObjects.get(object).objectpath;
+        if (!objectpath.matches(OBJECT_REGEX) || objectpath.length() > MAX_NAME_LENGTH)
+            throw new DBusException(getString("invalidObjectPath") + objectpath);
+        removeSigHandler(new DBusMatchRule(type, null, objectpath), handler);
+    }
+
+    protected abstract <T extends DBusSignal> void removeSigHandler(DBusMatchRule rule, DBusSigHandler<T> handler) throws DBusException;
+
+    /**
+     * Add a Signal Handler.
+     * Adds a signal handler to call when a signal is received which matches the specified type and name.
+     *
+     * @param type    The signal to watch for.
+     * @param handler The handler to call when a signal is received.
+     * @throws DBusException      If listening for the signal on the bus failed.
+     * @throws ClassCastException If type is not a sub-type of DBusSignal.
+     */
+    @SuppressWarnings("unchecked")
+    public <T extends DBusSignal> void addSigHandler(Class<T> type, DBusSigHandler<T> handler) throws DBusException {
+        if (!DBusSignal.class.isAssignableFrom(type)) throw new ClassCastException(getString("notDBusSignal"));
+        addSigHandler(new DBusMatchRule(type), (DBusSigHandler<? extends DBusSignal>) handler);
+    }
+
+    /**
+     * Add a Signal Handler.
+     * Adds a signal handler to call when a signal is received which matches the specified type, name and object.
+     *
+     * @param type    The signal to watch for.
+     * @param object  The object from which the signal will be emitted
+     * @param handler The handler to call when a signal is received.
+     * @throws DBusException      If listening for the signal on the bus failed.
+     * @throws ClassCastException If type is not a sub-type of DBusSignal.
+     */
+    @SuppressWarnings("unchecked")
+    public <T extends DBusSignal> void addSigHandler(Class<T> type, DBusInterface object, DBusSigHandler<T> handler) throws DBusException {
+        if (!DBusSignal.class.isAssignableFrom(type)) throw new ClassCastException(getString("notDBusSignal"));
+        String objectpath = importedObjects.get(object).objectpath;
+        if (!objectpath.matches(OBJECT_REGEX) || objectpath.length() > MAX_NAME_LENGTH)
+            throw new DBusException(getString("invalidObjectPath") + objectpath);
+        addSigHandler(new DBusMatchRule(type, null, objectpath), (DBusSigHandler<? extends DBusSignal>) handler);
+    }
+
+    protected abstract <T extends DBusSignal> void addSigHandler(DBusMatchRule rule, DBusSigHandler<T> handler) throws DBusException;
+
+    protected <T extends DBusSignal> void addSigHandlerWithoutMatch(Class<? extends DBusSignal> signal, DBusSigHandler<T> handler) throws DBusException {
+        DBusMatchRule rule = new DBusMatchRule(signal);
+        SignalTuple key = new SignalTuple(rule.getInterface(), rule.getMember(), rule.getObject(), rule.getSource());
+        synchronized (handledSignals) {
+            Vector<DBusSigHandler<? extends DBusSignal>> v = handledSignals.get(key);
+            if (null == v) {
+                v = new Vector<DBusSigHandler<? extends DBusSignal>>();
+                v.add(handler);
+                handledSignals.put(key, v);
+            } else
+                v.add(handler);
+        }
+    }
+
+    /**
+     * Disconnect from the Bus.
+     */
+    public void disconnect() {
+        connected = false;
+        if (Debug.debug) Debug.print(Debug.INFO, "Sending disconnected signal");
+        try {
+            handleMessage(new org.freedesktop.DBus.Local.Disconnected("/"));
+        } catch (Exception ee) {
+            if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, ee);
+        }
+
+        if (Debug.debug) Debug.print(Debug.INFO, "Disconnecting Abstract Connection");
+        // run all pending tasks.
+        while (runnables.size() > 0)
+            synchronized (runnables) {
+                runnables.notifyAll();
+            }
+
+        // stop the main thread
+        _run = false;
+
+        // unblock the sending thread.
+        synchronized (outgoing) {
+            outgoing.notifyAll();
+        }
+
+        // disconnect from the trasport layer
+        try {
+            if (null != transport) {
+                transport.disconnect();
+                transport = null;
+            }
+        } catch (IOException IOe) {
+            if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, IOe);
+        }
+
+        // stop all the workers
+        synchronized (workers) {
+            for (_workerthread t : workers)
+                t.halt();
+        }
+
+        // make sure none are blocking on the runnables queue still
+        synchronized (runnables) {
+            runnables.notifyAll();
+        }
+    }
+
+    public void finalize() {
+        disconnect();
+    }
+
+    /**
+     * Return any DBus error which has been received.
+     *
+     * @return A DBusExecutionException, or null if no error is pending.
+     */
+    public DBusExecutionException getError() {
+        synchronized (pendingErrors) {
+            if (pendingErrors.size() == 0) return null;
+            else
+                return pendingErrors.removeFirst().getException();
+        }
+    }
+
+    /**
+     * Call a method asynchronously and set a callback.
+     * This handler will be called in a separate thread.
+     *
+     * @param object     The remote object on which to call the method.
+     * @param m          The name of the method on the interface to call.
+     * @param callback   The callback handler.
+     * @param parameters The parameters to call the method with.
+     */
+    @SuppressWarnings("unchecked")
+    public <A> void callWithCallback(DBusInterface object, String m, CallbackHandler<A> callback, Object... parameters) {
+        if (Debug.debug) Debug.print(Debug.VERBOSE, "callWithCallback(" + object + "," + m + ", " + callback);
+        Class[] types = new Class[parameters.length];
+        for (int i = 0; i < parameters.length; i++)
+            types[i] = parameters[i].getClass();
+        RemoteObject ro = importedObjects.get(object);
+
+        try {
+            Method me;
+            if (null == ro.iface)
+                me = object.getClass().getMethod(m, types);
+            else
+                me = ro.iface.getMethod(m, types);
+            RemoteInvocationHandler.executeRemoteMethod(ro, me, this, RemoteInvocationHandler.CALL_TYPE_CALLBACK, callback, parameters);
+        } catch (DBusExecutionException DBEe) {
+            if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBEe);
+            throw DBEe;
+        } catch (Exception e) {
+            if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
+            throw new DBusExecutionException(e.getMessage());
+        }
+    }
+
+    /**
+     * Call a method asynchronously and get a handle with which to get the reply.
+     *
+     * @param object     The remote object on which to call the method.
+     * @param m          The name of the method on the interface to call.
+     * @param parameters The parameters to call the method with.
+     * @return A handle to the call.
+     */
+    @SuppressWarnings("unchecked")
+    public DBusAsyncReply callMethodAsync(DBusInterface object, String m, Object... parameters) {
+        Class<?>[] types = new Class[parameters.length];
+        for (int i = 0; i < parameters.length; i++)
+            types[i] = parameters[i].getClass();
+        RemoteObject ro = importedObjects.get(object);
+
+        try {
+            Method me;
+            if (null == ro.iface)
+                me = object.getClass().getMethod(m, types);
+            else
+                me = ro.iface.getMethod(m, types);
+            return (DBusAsyncReply) RemoteInvocationHandler.executeRemoteMethod(ro, me, this, RemoteInvocationHandler.CALL_TYPE_ASYNC, null, parameters);
+        } catch (DBusExecutionException DBEe) {
+            if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBEe);
+            throw DBEe;
+        } catch (Exception e) {
+            if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
+            throw new DBusExecutionException(e.getMessage());
+        }
+    }
+
+    private void handleMessage(final MethodCall m) throws DBusException {
+        if (Debug.debug) Debug.print(Debug.DEBUG, "Handling incoming method call: " + m);
+
+        ExportedObject eo = null;
+        Method meth = null;
+        Object o = null;
+
+        if (null == m.getInterface() ||
+                m.getInterface().equals("org.freedesktop.DBus.Peer") ||
+                m.getInterface().equals("org.freedesktop.DBus.Introspectable")) {
+            synchronized (exportedObjects) {
+                eo = exportedObjects.get(null);
+            }
+            if (null != eo && null == eo.object.get()) {
+                unExportObject(null);
+                eo = null;
+            }
+            if (null != eo) {
+                meth = eo.methods.get(new MethodTuple(m.getName(), m.getSig()));
+            }
+            if (null != meth)
+                o = new _globalhandler(m.getPath());
+            else
+                eo = null;
+        }
+        if (null == o) {
+            // now check for specific exported functions
+
+            synchronized (exportedObjects) {
+                eo = exportedObjects.get(m.getPath());
+            }
+            if (null != eo && null == eo.object.get()) {
+                if (Debug.debug) Debug.print(Debug.INFO, "Unexporting " + m.getPath() + " implicitly");
+                unExportObject(m.getPath());
+                eo = null;
+            }
+
+            if (null == eo) {
+                eo = fallbackcontainer.get(m.getPath());
+            }
+
+            if (null == eo) {
+                try {
+                    queueOutgoing(new Error(m, new DBus.Error.UnknownObject(m.getPath() + getString("notObjectProvidedByProcess"))));
+                } catch (DBusException DBe) {
+                }
+                return;
+            }
+            if (Debug.debug) {
+                Debug.print(Debug.VERBOSE, "Searching for method " + m.getName() + " with signature " + m.getSig());
+                Debug.print(Debug.VERBOSE, "List of methods on " + eo + ":");
+                for (MethodTuple mt : eo.methods.keySet())
+                    Debug.print(Debug.VERBOSE, "   " + mt + " => " + eo.methods.get(mt));
+            }
+            meth = eo.methods.get(new MethodTuple(m.getName(), m.getSig()));
+            if (null == meth) {
+                try {
+                    queueOutgoing(new Error(m, new DBus.Error.UnknownMethod(MessageFormat.format(getString("methodDoesNotExist"), new Object[]{m.getInterface(), m.getName()}))));
+                } catch (DBusException DBe) {
+                }
+                return;
+            }
+            o = eo.object.get();
+        }
+
+        // now execute it
+        final Method me = meth;
+        final Object ob = o;
+        final boolean noreply = (1 == (m.getFlags() & Message.Flags.NO_REPLY_EXPECTED));
+        final DBusCallInfo info = new DBusCallInfo(m);
+        final AbstractConnection conn = this;
+        if (Debug.debug) Debug.print(Debug.VERBOSE, "Adding Runnable for method " + meth);
+        addRunnable(new Runnable() {
+            private boolean run = false;
+
+            public synchronized void run() {
+                if (run) return;
+                run = true;
+                if (Debug.debug) Debug.print(Debug.DEBUG, "Running method " + me + " for remote call");
+                try {
+                    Type[] ts = me.getGenericParameterTypes();
+                    m.setArgs(Marshalling.deSerializeParameters(m.getParameters(), ts, conn));
+                    if (Debug.debug)
+                        Debug.print(Debug.VERBOSE, "Deserialised " + Arrays.deepToString(m.getParameters()) + " to types " + Arrays.deepToString(ts));
+                } catch (Exception e) {
+                    if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
+                    try {
+                        conn.queueOutgoing(new Error(m, new DBus.Error.UnknownMethod(getString("deSerializationFailure") + e)));
+                    } catch (DBusException DBe) {
+                    }
+                    return;
+                }
+
+                try {
+                    synchronized (infomap) {
+                        infomap.put(Thread.currentThread(), info);
+                    }
+                    Object result;
+                    try {
+                        if (Debug.debug)
+                            Debug.print(Debug.VERBOSE, "Invoking Method: " + me + " on " + ob + " with parameters " + Arrays.deepToString(m.getParameters()));
+                        result = me.invoke(ob, m.getParameters());
+                    } catch (InvocationTargetException ITe) {
+                        if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, ITe.getCause());
+                        throw ITe.getCause();
+                    }
+                    synchronized (infomap) {
+                        infomap.remove(Thread.currentThread());
+                    }
+                    if (!noreply) {
+                        MethodReturn reply;
+                        if (Void.TYPE.equals(me.getReturnType()))
+                            reply = new MethodReturn(m, null);
+                        else {
+                            StringBuffer sb = new StringBuffer();
+                            for (String s : Marshalling.getDBusType(me.getGenericReturnType()))
+                                sb.append(s);
+                            Object[] nr = Marshalling.convertParameters(new Object[]{result}, new Type[]{me.getGenericReturnType()}, conn);
+
+                            reply = new MethodReturn(m, sb.toString(), nr);
+                        }
+                        conn.queueOutgoing(reply);
+                    }
+                } catch (DBusExecutionException DBEe) {
+                    if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBEe);
+                    try {
+                        conn.queueOutgoing(new Error(m, DBEe));
+                    } catch (DBusException DBe) {
+                    }
+                } catch (Throwable e) {
+                    if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
+                    try {
+                        conn.queueOutgoing(new Error(m, new DBusExecutionException(MessageFormat.format(getString("errorExecutingMethod"), new Object[]{m.getInterface(), m.getName(), e.getMessage()}))));
+                    } catch (DBusException DBe) {
+                    }
+                }
+            }
+        });
+    }
+
+    @SuppressWarnings({"unchecked", "deprecation"})
+    private void handleMessage(final DBusSignal s) {
+        if (Debug.debug) Debug.print(Debug.DEBUG, "Handling incoming signal: " + s);
+        Vector<DBusSigHandler<? extends DBusSignal>> v = new Vector<DBusSigHandler<? extends DBusSignal>>();
+        synchronized (handledSignals) {
+            Vector<DBusSigHandler<? extends DBusSignal>> t;
+            t = handledSignals.get(new SignalTuple(s.getInterface(), s.getName(), null, null));
+            if (null != t) v.addAll(t);
+            t = handledSignals.get(new SignalTuple(s.getInterface(), s.getName(), s.getPath(), null));
+            if (null != t) v.addAll(t);
+            t = handledSignals.get(new SignalTuple(s.getInterface(), s.getName(), null, s.getSource()));
+            if (null != t) v.addAll(t);
+            t = handledSignals.get(new SignalTuple(s.getInterface(), s.getName(), s.getPath(), s.getSource()));
+            if (null != t) v.addAll(t);
+        }
+        if (0 == v.size()) return;
+        final AbstractConnection conn = this;
+        for (final DBusSigHandler<? extends DBusSignal> h : v) {
+            if (Debug.debug) Debug.print(Debug.VERBOSE, "Adding Runnable for signal " + s + " with handler " + h);
+            addRunnable(new Runnable() {
+                private boolean run = false;
+
+                public synchronized void run() {
+                    if (run) return;
+                    run = true;
+                    try {
+                        DBusSignal rs;
+                        if (s instanceof DBusSignal.internalsig || s.getClass().equals(DBusSignal.class))
+                            rs = s.createReal(conn);
+                        else
+                            rs = s;
+                        ((DBusSigHandler<DBusSignal>) h).handle(rs);
+                    } catch (DBusException DBe) {
+                        if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBe);
+                        try {
+                            conn.queueOutgoing(new Error(s, new DBusExecutionException("Error handling signal " + s.getInterface() + "." + s.getName() + ": " + DBe.getMessage())));
+                        } catch (DBusException DBe2) {
+                        }
+                    }
+                }
+            });
+        }
+    }
+
+    private void handleMessage(final Error err) {
+        if (Debug.debug) Debug.print(Debug.DEBUG, "Handling incoming error: " + err);
+        MethodCall m = null;
+        if (null == pendingCalls) return;
+        synchronized (pendingCalls) {
+            if (pendingCalls.contains(err.getReplySerial()))
+                m = pendingCalls.remove(err.getReplySerial());
+        }
+        if (null != m) {
+            m.setReply(err);
+            CallbackHandler cbh = null;
+            DBusAsyncReply asr = null;
+            synchronized (pendingCallbacks) {
+                cbh = pendingCallbacks.remove(m);
+                if (Debug.debug) Debug.print(Debug.VERBOSE, cbh + " = pendingCallbacks.remove(" + m + ")");
+                asr = pendingCallbackReplys.remove(m);
+            }
+            // queue callback for execution
+            if (null != cbh) {
+                final CallbackHandler fcbh = cbh;
+                if (Debug.debug) Debug.print(Debug.VERBOSE, "Adding Error Runnable with callback handler " + fcbh);
+                addRunnable(new Runnable() {
+                    private boolean run = false;
+
+                    public synchronized void run() {
+                        if (run) return;
+                        run = true;
+                        try {
+                            if (Debug.debug) Debug.print(Debug.VERBOSE, "Running Error Callback for " + err);
+                            DBusCallInfo info = new DBusCallInfo(err);
+                            synchronized (infomap) {
+                                infomap.put(Thread.currentThread(), info);
+                            }
+
+                            fcbh.handleError(err.getException());
+                            synchronized (infomap) {
+                                infomap.remove(Thread.currentThread());
+                            }
+
+                        } catch (Exception e) {
+                            if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
+                        }
+                    }
+                });
+            }
+
+        } else
+            synchronized (pendingErrors) {
+                pendingErrors.addLast(err);
+            }
+    }
+
+    @SuppressWarnings("unchecked")
+    private void handleMessage(final MethodReturn mr) {
+        if (Debug.debug) Debug.print(Debug.DEBUG, "Handling incoming method return: " + mr);
+        MethodCall m = null;
+        if (null == pendingCalls) return;
+        synchronized (pendingCalls) {
+            if (pendingCalls.contains(mr.getReplySerial()))
+                m = pendingCalls.remove(mr.getReplySerial());
+        }
+        if (null != m) {
+            m.setReply(mr);
+            mr.setCall(m);
+            CallbackHandler cbh = null;
+            DBusAsyncReply asr = null;
+            synchronized (pendingCallbacks) {
+                cbh = pendingCallbacks.remove(m);
+                if (Debug.debug) Debug.print(Debug.VERBOSE, cbh + " = pendingCallbacks.remove(" + m + ")");
+                asr = pendingCallbackReplys.remove(m);
+            }
+            // queue callback for execution
+            if (null != cbh) {
+                final CallbackHandler fcbh = cbh;
+                final DBusAsyncReply fasr = asr;
+                if (Debug.debug)
+                    Debug.print(Debug.VERBOSE, "Adding Runnable for method " + fasr.getMethod() + " with callback handler " + fcbh);
+                addRunnable(new Runnable() {
+                    private boolean run = false;
+
+                    public synchronized void run() {
+                        if (run) return;
+                        run = true;
+                        try {
+                            if (Debug.debug) Debug.print(Debug.VERBOSE, "Running Callback for " + mr);
+                            DBusCallInfo info = new DBusCallInfo(mr);
+                            synchronized (infomap) {
+                                infomap.put(Thread.currentThread(), info);
+                            }
+
+                            fcbh.handle(RemoteInvocationHandler.convertRV(mr.getSig(), mr.getParameters(), fasr.getMethod(), fasr.getConnection()));
+                            synchronized (infomap) {
+                                infomap.remove(Thread.currentThread());
+                            }
+
+                        } catch (Exception e) {
+                            if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
+                        }
+                    }
+                });
+            }
+
+        } else
+            try {
+                queueOutgoing(new Error(mr, new DBusExecutionException(getString("spuriousReply"))));
+            } catch (DBusException DBe) {
+            }
+    }
+
+    protected void sendMessage(Message m) {
+        try {
+            if (!connected) throw new NotConnected(getString("disconnected"));
+            if (m instanceof DBusSignal)
+                ((DBusSignal) m).appendbody(this);
+
+            if (m instanceof MethodCall) {
+                if (0 == (m.getFlags() & Message.Flags.NO_REPLY_EXPECTED))
+                    if (null == pendingCalls)
+                        ((MethodCall) m).setReply(new Error("org.freedesktop.DBus.Local", "org.freedesktop.DBus.Local.disconnected", 0, "s", new Object[]{getString("disconnected")}));
+                    else synchronized (pendingCalls) {
+                        pendingCalls.put(m.getSerial(), (MethodCall) m);
+                    }
+            }
+
+            transport.mout.writeMessage(m);
+
+        } catch (Exception e) {
+            if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
+            if (m instanceof MethodCall && e instanceof NotConnected)
+                try {
+                    ((MethodCall) m).setReply(new Error("org.freedesktop.DBus.Local", "org.freedesktop.DBus.Local.disconnected", 0, "s", new Object[]{getString("disconnected")}));
+                } catch (DBusException DBe) {
+                }
+            if (m instanceof MethodCall && e instanceof DBusExecutionException)
+                try {
+                    ((MethodCall) m).setReply(new Error(m, e));
+                } catch (DBusException DBe) {
+                }
+            else if (m instanceof MethodCall)
+                try {
+                    if (Debug.debug) Debug.print(Debug.INFO, "Setting reply to " + m + " as an error");
+                    ((MethodCall) m).setReply(new Error(m, new DBusExecutionException(getString("messageFailedSend") + e.getMessage())));
+                } catch (DBusException DBe) {
+                }
+            else if (m instanceof MethodReturn)
+                try {
+                    transport.mout.writeMessage(new Error(m, e));
+                } catch (IOException IOe) {
+                    if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, IOe);
+                } catch (DBusException IOe) {
+                    if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
+                }
+            if (e instanceof IOException) disconnect();
+        }
+    }
+
+    private Message readIncoming() throws DBusException {
+        if (!connected) throw new NotConnected(getString("missingTransport"));
+        Message m = null;
+        try {
+            m = transport.min.readMessage();
+        } catch (IOException IOe) {
+            throw new FatalDBusException(IOe.getMessage());
+        }
+        return m;
+    }
+
+    /**
+     * Returns the address this connection is connected to.
+     */
+    public BusAddress getAddress() throws ParseException {
+        return new BusAddress(addr);
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/ArrayFrob.java b/federation/sssd/src/main/java/org/freedesktop/dbus/ArrayFrob.java
new file mode 100644
index 0000000..86dfa52
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/ArrayFrob.java
@@ -0,0 +1,173 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import cx.ath.matthew.debug.Debug;
+
+import java.lang.reflect.Array;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Hashtable;
+import java.util.List;
+
+import static org.freedesktop.dbus.Gettext.getString;
+
+class ArrayFrob {
+    static Hashtable<Class<? extends Object>, Class<? extends Object>> primitiveToWrapper = new Hashtable<Class<? extends Object>, Class<? extends Object>>();
+    static Hashtable<Class<? extends Object>, Class<? extends Object>> wrapperToPrimitive = new Hashtable<Class<? extends Object>, Class<? extends Object>>();
+
+    static {
+        primitiveToWrapper.put(Boolean.TYPE, Boolean.class);
+        primitiveToWrapper.put(Byte.TYPE, Byte.class);
+        primitiveToWrapper.put(Short.TYPE, Short.class);
+        primitiveToWrapper.put(Character.TYPE, Character.class);
+        primitiveToWrapper.put(Integer.TYPE, Integer.class);
+        primitiveToWrapper.put(Long.TYPE, Long.class);
+        primitiveToWrapper.put(Float.TYPE, Float.class);
+        primitiveToWrapper.put(Double.TYPE, Double.class);
+        wrapperToPrimitive.put(Boolean.class, Boolean.TYPE);
+        wrapperToPrimitive.put(Byte.class, Byte.TYPE);
+        wrapperToPrimitive.put(Short.class, Short.TYPE);
+        wrapperToPrimitive.put(Character.class, Character.TYPE);
+        wrapperToPrimitive.put(Integer.class, Integer.TYPE);
+        wrapperToPrimitive.put(Long.class, Long.TYPE);
+        wrapperToPrimitive.put(Float.class, Float.TYPE);
+        wrapperToPrimitive.put(Double.class, Double.TYPE);
+
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T> T[] wrap(Object o) throws IllegalArgumentException {
+        Class<? extends Object> ac = o.getClass();
+        if (!ac.isArray()) throw new IllegalArgumentException(getString("invalidArray"));
+        Class<? extends Object> cc = ac.getComponentType();
+        Class<? extends Object> ncc = primitiveToWrapper.get(cc);
+        if (null == ncc) throw new IllegalArgumentException(getString("notPrimitiveType"));
+        T[] ns = (T[]) Array.newInstance(ncc, Array.getLength(o));
+        for (int i = 0; i < ns.length; i++)
+            ns[i] = (T) Array.get(o, i);
+        return ns;
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T> Object unwrap(T[] ns) throws IllegalArgumentException {
+        Class<? extends T[]> ac = (Class<? extends T[]>) ns.getClass();
+        Class<T> cc = (Class<T>) ac.getComponentType();
+        Class<? extends Object> ncc = wrapperToPrimitive.get(cc);
+        if (null == ncc) throw new IllegalArgumentException(getString("invalidWrapperType"));
+        Object o = Array.newInstance(ncc, ns.length);
+        for (int i = 0; i < ns.length; i++)
+            Array.set(o, i, ns[i]);
+        return o;
+    }
+
+    public static <T> List<T> listify(T[] ns) throws IllegalArgumentException {
+        return Arrays.asList(ns);
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T> List<T> listify(Object o) throws IllegalArgumentException {
+        if (o instanceof Object[]) return listify((T[]) o);
+        if (!o.getClass().isArray()) throw new IllegalArgumentException(getString("invalidArray"));
+        List<T> l = new ArrayList<T>(Array.getLength(o));
+        for (int i = 0; i < Array.getLength(o); i++)
+            l.add((T) Array.get(o, i));
+        return l;
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T> T[] delist(List<T> l, Class<T> c) throws IllegalArgumentException {
+        return l.toArray((T[]) Array.newInstance(c, 0));
+    }
+
+    public static <T> Object delistprimitive(List<T> l, Class<T> c) throws IllegalArgumentException {
+        Object o = Array.newInstance(c, l.size());
+        for (int i = 0; i < l.size(); i++)
+            Array.set(o, i, l.get(i));
+        return o;
+    }
+
+    @SuppressWarnings("unchecked")
+    public static Object convert(Object o, Class<? extends Object> c) throws IllegalArgumentException {
+      /* Possible Conversions:
+       *
+       ** List<Integer> -> List<Integer>
+       ** List<Integer> -> int[]
+       ** List<Integer> -> Integer[]
+       ** int[] -> int[]
+       ** int[] -> List<Integer>
+       ** int[] -> Integer[]
+       ** Integer[] -> Integer[]
+       ** Integer[] -> int[]
+       ** Integer[] -> List<Integer>
+       */
+        try {
+            // List<Integer> -> List<Integer>
+            if (List.class.equals(c)
+                    && o instanceof List)
+                return o;
+
+            // int[] -> List<Integer>
+            // Integer[] -> List<Integer>
+            if (List.class.equals(c)
+                    && o.getClass().isArray())
+                return listify(o);
+
+            // int[] -> int[]
+            // Integer[] -> Integer[]
+            if (o.getClass().isArray()
+                    && c.isArray()
+                    && o.getClass().getComponentType().equals(c.getComponentType()))
+                return o;
+
+            // int[] -> Integer[]
+            if (o.getClass().isArray()
+                    && c.isArray()
+                    && o.getClass().getComponentType().isPrimitive())
+                return wrap(o);
+
+            // Integer[] -> int[]
+            if (o.getClass().isArray()
+                    && c.isArray()
+                    && c.getComponentType().isPrimitive())
+                return unwrap((Object[]) o);
+
+            // List<Integer> -> int[]
+            if (o instanceof List
+                    && c.isArray()
+                    && c.getComponentType().isPrimitive())
+                return delistprimitive((List<Object>) o, (Class<Object>) c.getComponentType());
+
+            // List<Integer> -> Integer[]
+            if (o instanceof List
+                    && c.isArray())
+                return delist((List<Object>) o, (Class<Object>) c.getComponentType());
+
+            if (o.getClass().isArray()
+                    && c.isArray())
+                return type((Object[]) o, (Class<Object>) c.getComponentType());
+
+        } catch (Exception e) {
+            if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
+            throw new IllegalArgumentException(e);
+        }
+
+        throw new IllegalArgumentException(MessageFormat.format(getString("convertionTypeNotExpected"), new Object[]{o.getClass(), c}));
+    }
+
+    public static Object[] type(Object[] old, Class<Object> c) {
+        Object[] ns = (Object[]) Array.newInstance(c, old.length);
+        for (int i = 0; i < ns.length; i++)
+            ns[i] = old[i];
+        return ns;
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/BusAddress.java b/federation/sssd/src/main/java/org/freedesktop/dbus/BusAddress.java
new file mode 100644
index 0000000..3848951
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/BusAddress.java
@@ -0,0 +1,52 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import cx.ath.matthew.debug.Debug;
+
+import java.text.ParseException;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.freedesktop.dbus.Gettext.getString;
+
+public class BusAddress {
+    private String type;
+    private Map<String, String> parameters;
+
+    public BusAddress(String address) throws ParseException {
+        if (null == address || "".equals(address)) throw new ParseException(getString("busAddressBlank"), 0);
+        if (Debug.debug) Debug.print(Debug.VERBOSE, "Parsing bus address: " + address);
+        String[] ss = address.split(":", 2);
+        if (ss.length < 2) throw new ParseException(getString("busAddressInvalid") + address, 0);
+        type = ss[0];
+        if (Debug.debug) Debug.print(Debug.VERBOSE, "Transport type: " + type);
+        String[] ps = ss[1].split(",");
+        parameters = new HashMap<String, String>();
+        for (String p : ps) {
+            String[] kv = p.split("=", 2);
+            parameters.put(kv[0], kv[1]);
+        }
+        if (Debug.debug) Debug.print(Debug.VERBOSE, "Transport options: " + parameters);
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public String getParameter(String key) {
+        return parameters.get(key);
+    }
+
+    public String toString() {
+        return type + ": " + parameters;
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/CallbackHandler.java b/federation/sssd/src/main/java/org/freedesktop/dbus/CallbackHandler.java
new file mode 100644
index 0000000..0e2a81e
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/CallbackHandler.java
@@ -0,0 +1,22 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.dbus.exceptions.DBusExecutionException;
+
+/**
+ * Interface for callbacks in async mode
+ */
+public interface CallbackHandler<ReturnType> {
+    public void handle(ReturnType r);
+
+    public void handleError(DBusExecutionException e);
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/Container.java b/federation/sssd/src/main/java/org/freedesktop/dbus/Container.java
new file mode 100644
index 0000000..39fd245
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/Container.java
@@ -0,0 +1,93 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Type;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This class is the super class of both Structs and Tuples
+ * and holds common methods.
+ */
+abstract class Container {
+    private static Map<Type, Type[]> typecache = new HashMap<Type, Type[]>();
+
+    static void putTypeCache(Type k, Type[] v) {
+        typecache.put(k, v);
+    }
+
+    static Type[] getTypeCache(Type k) {
+        return typecache.get(k);
+    }
+
+    private Object[] parameters = null;
+
+    public Container() {
+    }
+
+    private void setup() {
+        Field[] fs = getClass().getDeclaredFields();
+        Object[] args = new Object[fs.length];
+
+        int diff = 0;
+        for (Field f : fs) {
+            Position p = f.getAnnotation(Position.class);
+            if (null == p) {
+                diff++;
+                continue;
+            }
+            try {
+                args[p.value()] = f.get(this);
+            } catch (IllegalAccessException IAe) {
+            }
+        }
+
+        this.parameters = new Object[args.length - diff];
+        System.arraycopy(args, 0, parameters, 0, parameters.length);
+    }
+
+    /**
+     * Returns the struct contents in order.
+     *
+     * @throws DBusException If there is  a problem doing this.
+     */
+    public final Object[] getParameters() {
+        if (null != parameters) return parameters;
+        setup();
+        return parameters;
+    }
+
+    /**
+     * Returns this struct as a string.
+     */
+    public final String toString() {
+        String s = getClass().getName() + "<";
+        if (null == parameters)
+            setup();
+        if (0 == parameters.length)
+            return s + ">";
+        for (Object o : parameters)
+            s += o + ", ";
+        return s.replaceAll(", $", ">");
+    }
+
+    public final boolean equals(Object other) {
+        if (other instanceof Container) {
+            Container that = (Container) other;
+            if (this.getClass().equals(that.getClass()))
+                return Arrays.equals(this.getParameters(), that.getParameters());
+            else return false;
+        } else return false;
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/DBusAsyncReply.java b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusAsyncReply.java
new file mode 100644
index 0000000..51c2bfd
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusAsyncReply.java
@@ -0,0 +1,117 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import cx.ath.matthew.debug.Debug;
+import org.freedesktop.DBus.Error.NoReply;
+import org.freedesktop.dbus.exceptions.DBusException;
+import org.freedesktop.dbus.exceptions.DBusExecutionException;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+
+import static org.freedesktop.dbus.Gettext.getString;
+
+/**
+ * A handle to an asynchronous method call.
+ */
+public class DBusAsyncReply<ReturnType> {
+    /**
+     * Check if any of a set of asynchronous calls have had a reply.
+     *
+     * @param replies A Collection of handles to replies to check.
+     * @return A Collection only containing those calls which have had replies.
+     */
+    public static Collection<DBusAsyncReply<? extends Object>> hasReply(Collection<DBusAsyncReply<? extends Object>> replies) {
+        Collection<DBusAsyncReply<? extends Object>> c = new ArrayList<DBusAsyncReply<? extends Object>>(replies);
+        Iterator<DBusAsyncReply<? extends Object>> i = c.iterator();
+        while (i.hasNext())
+            if (!i.next().hasReply()) i.remove();
+        return c;
+    }
+
+    private ReturnType rval = null;
+    private DBusExecutionException error = null;
+    private MethodCall mc;
+    private Method me;
+    private AbstractConnection conn;
+
+    DBusAsyncReply(MethodCall mc, Method me, AbstractConnection conn) {
+        this.mc = mc;
+        this.me = me;
+        this.conn = conn;
+    }
+
+    @SuppressWarnings("unchecked")
+    private synchronized void checkReply() {
+        if (mc.hasReply()) {
+            Message m = mc.getReply();
+            if (m instanceof Error)
+                error = ((Error) m).getException();
+            else if (m instanceof MethodReturn) {
+                try {
+                    rval = (ReturnType) RemoteInvocationHandler.convertRV(m.getSig(), m.getParameters(), me, conn);
+                } catch (DBusExecutionException DBEe) {
+                    error = DBEe;
+                } catch (DBusException DBe) {
+                    if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBe);
+                    error = new DBusExecutionException(DBe.getMessage());
+                }
+            }
+        }
+    }
+
+    /**
+     * Check if we've had a reply.
+     *
+     * @return True if we have a reply
+     */
+    public boolean hasReply() {
+        if (null != rval || null != error) return true;
+        checkReply();
+        return null != rval || null != error;
+    }
+
+    /**
+     * Get the reply.
+     *
+     * @return The return value from the method.
+     * @throws DBusExecutionException if the reply to the method was an error.
+     * @throws NoReply                if the method hasn't had a reply yet
+     */
+    public ReturnType getReply() throws DBusExecutionException {
+        if (null != rval) return rval;
+        else if (null != error) throw error;
+        checkReply();
+        if (null != rval) return rval;
+        else if (null != error) throw error;
+        else throw new NoReply(getString("asyncCallNoReply"));
+    }
+
+    public String toString() {
+        return getString("waitingFor") + mc;
+    }
+
+    Method getMethod() {
+        return me;
+    }
+
+    AbstractConnection getConnection() {
+        return conn;
+    }
+
+    MethodCall getCall() {
+        return mc;
+    }
+}
+
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/DBusCallInfo.java b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusCallInfo.java
new file mode 100644
index 0000000..1c9d143
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusCallInfo.java
@@ -0,0 +1,79 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+/**
+ * Holds information on a method call
+ */
+public class DBusCallInfo {
+    /**
+     * Indicates the caller won't wait for a reply (and we won't send one).
+     */
+    public static final int NO_REPLY = Message.Flags.NO_REPLY_EXPECTED;
+    public static final int ASYNC = 0x100;
+    private String source;
+    private String destination;
+    private String objectpath;
+    private String iface;
+    private String method;
+    private int flags;
+
+    DBusCallInfo(Message m) {
+        this.source = m.getSource();
+        this.destination = m.getDestination();
+        this.objectpath = m.getPath();
+        this.iface = m.getInterface();
+        this.method = m.getName();
+        this.flags = m.getFlags();
+    }
+
+    /**
+     * Returns the BusID which called the method
+     */
+    public String getSource() {
+        return source;
+    }
+
+    /**
+     * Returns the name with which we were addressed on the Bus
+     */
+    public String getDestination() {
+        return destination;
+    }
+
+    /**
+     * Returns the object path used to call this method
+     */
+    public String getObjectPath() {
+        return objectpath;
+    }
+
+    /**
+     * Returns the interface this method was called with
+     */
+    public String getInterface() {
+        return iface;
+    }
+
+    /**
+     * Returns the method name used to call this method
+     */
+    public String getMethod() {
+        return method;
+    }
+
+    /**
+     * Returns any flags set on this method call
+     */
+    public int getFlags() {
+        return flags;
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/DBusConnection.java b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusConnection.java
new file mode 100644
index 0000000..45e33a4
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusConnection.java
@@ -0,0 +1,794 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import cx.ath.matthew.debug.Debug;
+import org.freedesktop.DBus;
+import org.freedesktop.dbus.exceptions.DBusException;
+import org.freedesktop.dbus.exceptions.DBusExecutionException;
+import org.freedesktop.dbus.exceptions.NotConnected;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.lang.reflect.Proxy;
+import java.text.MessageFormat;
+import java.text.ParseException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.Vector;
+
+import static org.freedesktop.dbus.Gettext.getString;
+
+/**
+ * Handles a connection to DBus.
+ * <p>
+ * This is a Singleton class, only 1 connection to the SYSTEM or SESSION busses can be made.
+ * Repeated calls to getConnection will return the same reference.
+ * </p>
+ * <p>
+ * Signal Handlers and method calls from remote objects are run in their own threads, you MUST handle the concurrency issues.
+ * </p>
+ */
+public class DBusConnection extends AbstractConnection {
+    /**
+     * Add addresses of peers to a set which will watch for them to
+     * disappear and automatically remove them from the set.
+     */
+    public class PeerSet implements Set<String>, DBusSigHandler<DBus.NameOwnerChanged> {
+        private Set<String> addresses;
+
+        public PeerSet() {
+            addresses = new TreeSet<String>();
+            try {
+                addSigHandler(new DBusMatchRule(DBus.NameOwnerChanged.class, null, null), this);
+            } catch (DBusException DBe) {
+                if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBe);
+            }
+        }
+
+        public void handle(DBus.NameOwnerChanged noc) {
+            if (Debug.debug)
+                Debug.print(Debug.DEBUG, "Received NameOwnerChanged(" + noc.name + "," + noc.old_owner + "," + noc.new_owner + ")");
+            if ("".equals(noc.new_owner) && addresses.contains(noc.name))
+                remove(noc.name);
+        }
+
+        public boolean add(String address) {
+            if (Debug.debug)
+                Debug.print(Debug.DEBUG, "Adding " + address);
+            synchronized (addresses) {
+                return addresses.add(address);
+            }
+        }
+
+        public boolean addAll(Collection<? extends String> addresses) {
+            synchronized (this.addresses) {
+                return this.addresses.addAll(addresses);
+            }
+        }
+
+        public void clear() {
+            synchronized (addresses) {
+                addresses.clear();
+            }
+        }
+
+        public boolean contains(Object o) {
+            return addresses.contains(o);
+        }
+
+        public boolean containsAll(Collection<?> os) {
+            return addresses.containsAll(os);
+        }
+
+        public boolean equals(Object o) {
+            if (o instanceof PeerSet)
+                return ((PeerSet) o).addresses.equals(addresses);
+            else return false;
+        }
+
+        public int hashCode() {
+            return addresses.hashCode();
+        }
+
+        public boolean isEmpty() {
+            return addresses.isEmpty();
+        }
+
+        public Iterator<String> iterator() {
+            return addresses.iterator();
+        }
+
+        public boolean remove(Object o) {
+            if (Debug.debug)
+                Debug.print(Debug.DEBUG, "Removing " + o);
+            synchronized (addresses) {
+                return addresses.remove(o);
+            }
+        }
+
+        public boolean removeAll(Collection<?> os) {
+            synchronized (addresses) {
+                return addresses.removeAll(os);
+            }
+        }
+
+        public boolean retainAll(Collection<?> os) {
+            synchronized (addresses) {
+                return addresses.retainAll(os);
+            }
+        }
+
+        public int size() {
+            return addresses.size();
+        }
+
+        public Object[] toArray() {
+            synchronized (addresses) {
+                return addresses.toArray();
+            }
+        }
+
+        public <T> T[] toArray(T[] a) {
+            synchronized (addresses) {
+                return addresses.toArray(a);
+            }
+        }
+    }
+
+    private class _sighandler implements DBusSigHandler<DBusSignal> {
+        public void handle(DBusSignal s) {
+            if (s instanceof org.freedesktop.DBus.Local.Disconnected) {
+                if (Debug.debug) Debug.print(Debug.WARN, "Handling disconnected signal from bus");
+                try {
+                    Error err = new Error(
+                            "org.freedesktop.DBus.Local", "org.freedesktop.DBus.Local.disconnected", 0, "s", new Object[]{getString("disconnected")});
+                    if (null != pendingCalls) synchronized (pendingCalls) {
+                        long[] set = pendingCalls.getKeys();
+                        for (long l : set)
+                            if (-1 != l) {
+                                MethodCall m = pendingCalls.remove(l);
+                                if (null != m)
+                                    m.setReply(err);
+                            }
+                    }
+                    synchronized (pendingErrors) {
+                        pendingErrors.add(err);
+                    }
+                } catch (DBusException DBe) {
+                }
+            } else if (s instanceof org.freedesktop.DBus.NameAcquired) {
+                busnames.add(((org.freedesktop.DBus.NameAcquired) s).name);
+            }
+        }
+    }
+
+    /**
+     * System Bus
+     */
+    public static final int SYSTEM = 0;
+    /**
+     * Session Bus
+     */
+    public static final int SESSION = 1;
+
+    public static final String DEFAULT_SYSTEM_BUS_ADDRESS = "unix:path=/var/run/dbus/system_bus_socket";
+
+    private List<String> busnames;
+
+    private static final Map<Object, DBusConnection> conn = new HashMap<Object, DBusConnection>();
+    private int _refcount = 0;
+    private Object _reflock = new Object();
+    private DBus _dbus;
+
+    /**
+     * Connect to the BUS. If a connection already exists to the specified Bus, a reference to it is returned.
+     *
+     * @param address The address of the bus to connect to
+     * @throws DBusException If there is a problem connecting to the Bus.
+     */
+    public static DBusConnection getConnection(String address) throws DBusException {
+        synchronized (conn) {
+            DBusConnection c = conn.get(address);
+            if (null != c) {
+                synchronized (c._reflock) {
+                    c._refcount++;
+                }
+                return c;
+            } else {
+                c = new DBusConnection(address);
+                conn.put(address, c);
+                return c;
+            }
+        }
+    }
+
+    /**
+     * Connect to the BUS. If a connection already exists to the specified Bus, a reference to it is returned.
+     *
+     * @param bustype The Bus to connect to.
+     * @throws DBusException If there is a problem connecting to the Bus.
+     * @see #SYSTEM
+     * @see #SESSION
+     */
+    public static DBusConnection getConnection(int bustype) throws DBusException {
+        synchronized (conn) {
+            String s = null;
+            switch (bustype) {
+                case SYSTEM:
+                    s = System.getenv("DBUS_SYSTEM_BUS_ADDRESS");
+                    if (null == s) s = DEFAULT_SYSTEM_BUS_ADDRESS;
+                    break;
+                case SESSION:
+                    s = System.getenv("DBUS_SESSION_BUS_ADDRESS");
+                    if (null == s) {
+                        // address gets stashed in $HOME/.dbus/session-bus/`dbus-uuidgen --get`-`sed 's/:\(.\)\..*/\1/' <<< $DISPLAY`
+                        String display = System.getenv("DISPLAY");
+                        if (null == display) throw new DBusException(getString("cannotResolveSessionBusAddress"));
+                        File uuidfile = new File("/var/lib/dbus/machine-id");
+                        if (!uuidfile.exists()) throw new DBusException(getString("cannotResolveSessionBusAddress"));
+                        try {
+                            BufferedReader r = new BufferedReader(new FileReader(uuidfile));
+                            String uuid = r.readLine();
+                            String homedir = System.getProperty("user.home");
+                            File addressfile = new File(homedir + "/.dbus/session-bus",
+                                    uuid + "-" + display.replaceAll(":([0-9]*)\\..*", "$1"));
+                            if (!addressfile.exists())
+                                throw new DBusException(getString("cannotResolveSessionBusAddress"));
+                            r = new BufferedReader(new FileReader(addressfile));
+                            String l;
+                            while (null != (l = r.readLine())) {
+                                if (Debug.debug) Debug.print(Debug.VERBOSE, "Reading D-Bus session data: " + l);
+                                if (l.matches("DBUS_SESSION_BUS_ADDRESS.*")) {
+                                    s = l.replaceAll("^[^=]*=", "");
+                                    if (Debug.debug) Debug.print(Debug.VERBOSE, "Parsing " + l + " to " + s);
+                                }
+                            }
+                            if (null == s || "".equals(s))
+                                throw new DBusException(getString("cannotResolveSessionBusAddress"));
+                            if (Debug.debug)
+                                Debug.print(Debug.INFO, "Read bus address " + s + " from file " + addressfile.toString());
+                        } catch (Exception e) {
+                            if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
+                            throw new DBusException(getString("cannotResolveSessionBusAddress"));
+                        }
+                    }
+                    break;
+                default:
+                    throw new DBusException(getString("invalidBusType") + bustype);
+            }
+            DBusConnection c = conn.get(s);
+            if (Debug.debug) Debug.print(Debug.VERBOSE, "Getting bus connection for " + s + ": " + c);
+            if (null != c) {
+                synchronized (c._reflock) {
+                    c._refcount++;
+                }
+                return c;
+            } else {
+                if (Debug.debug) Debug.print(Debug.DEBUG, "Creating new bus connection to: " + s);
+                c = new DBusConnection(s);
+                conn.put(s, c);
+                return c;
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private DBusConnection(String address) throws DBusException {
+        super(address);
+        busnames = new Vector<String>();
+
+        synchronized (_reflock) {
+            _refcount = 1;
+        }
+
+        try {
+            transport = new Transport(addr, AbstractConnection.TIMEOUT);
+            connected = true;
+        } catch (IOException IOe) {
+            if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, IOe);
+            disconnect();
+            throw new DBusException(getString("connectionFailure") + IOe.getMessage());
+        } catch (ParseException Pe) {
+            if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, Pe);
+            disconnect();
+            throw new DBusException(getString("connectionFailure") + Pe.getMessage());
+        }
+
+        // start listening for calls
+        listen();
+
+        // register disconnect handlers
+        DBusSigHandler h = new _sighandler();
+        addSigHandlerWithoutMatch(org.freedesktop.DBus.Local.Disconnected.class, h);
+        addSigHandlerWithoutMatch(org.freedesktop.DBus.NameAcquired.class, h);
+
+        // register ourselves
+        _dbus = getRemoteObject("org.freedesktop.DBus", "/org/freedesktop/DBus", DBus.class);
+        try {
+            busnames.add(_dbus.Hello());
+        } catch (DBusExecutionException DBEe) {
+            if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBEe);
+            throw new DBusException(DBEe.getMessage());
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    DBusInterface dynamicProxy(String source, String path) throws DBusException {
+        if (Debug.debug)
+            Debug.print(Debug.INFO, "Introspecting " + path + " on " + source + " for dynamic proxy creation");
+        try {
+            DBus.Introspectable intro = getRemoteObject(source, path, DBus.Introspectable.class);
+            String data = intro.Introspect();
+            if (Debug.debug) Debug.print(Debug.VERBOSE, "Got introspection data: " + data);
+            String[] tags = data.split("[<>]");
+            Vector<String> ifaces = new Vector<String>();
+            for (String tag : tags) {
+                if (tag.startsWith("interface")) {
+                    ifaces.add(tag.replaceAll("^interface *name *= *['\"]([^'\"]*)['\"].*$", "$1"));
+                }
+            }
+            Vector<Class<? extends Object>> ifcs = new Vector<Class<? extends Object>>();
+            for (String iface : ifaces) {
+                if (Debug.debug) Debug.print(Debug.DEBUG, "Trying interface " + iface);
+                int j = 0;
+                while (j >= 0) {
+                    try {
+                        Class ifclass = Class.forName(iface);
+                        if (!ifcs.contains(ifclass))
+                            ifcs.add(ifclass);
+                        break;
+                    } catch (Exception e) {
+                    }
+                    j = iface.lastIndexOf(".");
+                    char[] cs = iface.toCharArray();
+                    if (j >= 0) {
+                        cs[j] = '$';
+                        iface = String.valueOf(cs);
+                    }
+                }
+            }
+
+            if (ifcs.size() == 0) throw new DBusException(getString("interfaceToCastNotFound"));
+
+            RemoteObject ro = new RemoteObject(source, path, null, false);
+            DBusInterface newi = (DBusInterface)
+                    Proxy.newProxyInstance(ifcs.get(0).getClassLoader(),
+                            ifcs.toArray(new Class[0]),
+                            new RemoteInvocationHandler(this, ro));
+            importedObjects.put(newi, ro);
+            return newi;
+        } catch (Exception e) {
+            if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
+            throw new DBusException(MessageFormat.format(getString("createProxyExportFailure"), new Object[]{path, source, e.getMessage()}));
+        }
+    }
+
+    DBusInterface getExportedObject(String source, String path) throws DBusException {
+        ExportedObject o = null;
+        synchronized (exportedObjects) {
+            o = exportedObjects.get(path);
+        }
+        if (null != o && null == o.object.get()) {
+            unExportObject(path);
+            o = null;
+        }
+        if (null != o) return o.object.get();
+        if (null == source) throw new DBusException(getString("objectNotExportedNoRemoteSpecified"));
+        return dynamicProxy(source, path);
+    }
+
+    /**
+     * Release a bus name.
+     * Releases the name so that other people can use it
+     *
+     * @param busname The name to release. MUST be in dot-notation like "org.freedesktop.local"
+     * @throws DBusException If the busname is incorrectly formatted.
+     */
+    public void releaseBusName(String busname) throws DBusException {
+        if (!busname.matches(BUSNAME_REGEX) || busname.length() > MAX_NAME_LENGTH)
+            throw new DBusException(getString("invalidBusName"));
+        synchronized (this.busnames) {
+            UInt32 rv;
+            try {
+                rv = _dbus.ReleaseName(busname);
+            } catch (DBusExecutionException DBEe) {
+                if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBEe);
+                throw new DBusException(DBEe.getMessage());
+            }
+            this.busnames.remove(busname);
+        }
+    }
+
+    /**
+     * Request a bus name.
+     * Request the well known name that this should respond to on the Bus.
+     *
+     * @param busname The name to respond to. MUST be in dot-notation like "org.freedesktop.local"
+     * @throws DBusException If the register name failed, or our name already exists on the bus.
+     *                       or if busname is incorrectly formatted.
+     */
+    public void requestBusName(String busname) throws DBusException {
+        if (!busname.matches(BUSNAME_REGEX) || busname.length() > MAX_NAME_LENGTH)
+            throw new DBusException(getString("invalidBusName"));
+        synchronized (this.busnames) {
+            UInt32 rv;
+            try {
+                rv = _dbus.RequestName(busname,
+                        new UInt32(DBus.DBUS_NAME_FLAG_REPLACE_EXISTING |
+                                DBus.DBUS_NAME_FLAG_DO_NOT_QUEUE));
+            } catch (DBusExecutionException DBEe) {
+                if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBEe);
+                throw new DBusException(DBEe.getMessage());
+            }
+            switch (rv.intValue()) {
+                case DBus.DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
+                    break;
+                case DBus.DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
+                    throw new DBusException(getString("dbusRegistrationFailure"));
+                case DBus.DBUS_REQUEST_NAME_REPLY_EXISTS:
+                    throw new DBusException(getString("dbusRegistrationFailure"));
+                case DBus.DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
+                    break;
+                default:
+                    break;
+            }
+            this.busnames.add(busname);
+        }
+    }
+
+    /**
+     * Returns the unique name of this connection.
+     */
+    public String getUniqueName() {
+        return busnames.get(0);
+    }
+
+    /**
+     * Returns all the names owned by this connection.
+     */
+    public String[] getNames() {
+        Set<String> names = new TreeSet<String>();
+        names.addAll(busnames);
+        return names.toArray(new String[0]);
+    }
+
+    public <I extends DBusInterface> I getPeerRemoteObject(String busname, String objectpath, Class<I> type) throws DBusException {
+        return getPeerRemoteObject(busname, objectpath, type, true);
+    }
+
+    /**
+     * Return a reference to a remote object.
+     * This method will resolve the well known name (if given) to a unique bus name when you call it.
+     * This means that if a well known name is released by one process and acquired by another calls to
+     * objects gained from this method will continue to operate on the original process.
+     * <p>
+     * This method will use bus introspection to determine the interfaces on a remote object and so
+     * <b>may block</b> and <b>may fail</b>. The resulting proxy object will, however, be castable
+     * to any interface it implements. It will also autostart the process if applicable. Also note
+     * that the resulting proxy may fail to execute the correct method with overloaded methods
+     * and that complex types may fail in interesting ways. Basically, if something odd happens,
+     * try specifying the interface explicitly.
+     *
+     * @param busname    The bus name to connect to. Usually a well known bus name in dot-notation (such as "org.freedesktop.local")
+     *                   or may be a DBus address such as ":1-16".
+     * @param objectpath The path on which the process is exporting the object.$
+     * @return A reference to a remote object.
+     * @throws ClassCastException If type is not a sub-type of DBusInterface
+     * @throws DBusException      If busname or objectpath are incorrectly formatted.
+     */
+    public DBusInterface getPeerRemoteObject(String busname, String objectpath) throws DBusException {
+        if (null == busname) throw new DBusException(getString("nullBusName"));
+
+        if ((!busname.matches(BUSNAME_REGEX) && !busname.matches(CONNID_REGEX))
+                || busname.length() > MAX_NAME_LENGTH)
+            throw new DBusException(getString("invalidBusName") + busname);
+
+        String unique = _dbus.GetNameOwner(busname);
+
+        return dynamicProxy(unique, objectpath);
+    }
+
+    /**
+     * Return a reference to a remote object.
+     * This method will always refer to the well known name (if given) rather than resolving it to a unique bus name.
+     * In particular this means that if a process providing the well known name disappears and is taken over by another process
+     * proxy objects gained by this method will make calls on the new proccess.
+     * <p>
+     * This method will use bus introspection to determine the interfaces on a remote object and so
+     * <b>may block</b> and <b>may fail</b>. The resulting proxy object will, however, be castable
+     * to any interface it implements. It will also autostart the process if applicable. Also note
+     * that the resulting proxy may fail to execute the correct method with overloaded methods
+     * and that complex types may fail in interesting ways. Basically, if something odd happens,
+     * try specifying the interface explicitly.
+     *
+     * @param busname    The bus name to connect to. Usually a well known bus name name in dot-notation (such as "org.freedesktop.local")
+     *                   or may be a DBus address such as ":1-16".
+     * @param objectpath The path on which the process is exporting the object.
+     * @return A reference to a remote object.
+     * @throws ClassCastException If type is not a sub-type of DBusInterface
+     * @throws DBusException      If busname or objectpath are incorrectly formatted.
+     */
+    public DBusInterface getRemoteObject(String busname, String objectpath) throws DBusException {
+        if (null == busname) throw new DBusException(getString("nullBusName"));
+        if (null == objectpath) throw new DBusException(getString("nullObjectPath"));
+
+        if ((!busname.matches(BUSNAME_REGEX) && !busname.matches(CONNID_REGEX))
+                || busname.length() > MAX_NAME_LENGTH)
+            throw new DBusException(getString("invalidBusName") + busname);
+
+        if (!objectpath.matches(OBJECT_REGEX) || objectpath.length() > MAX_NAME_LENGTH)
+            throw new DBusException(getString("invalidObjectPath") + objectpath);
+
+        return dynamicProxy(busname, objectpath);
+    }
+
+    /**
+     * Return a reference to a remote object.
+     * This method will resolve the well known name (if given) to a unique bus name when you call it.
+     * This means that if a well known name is released by one process and acquired by another calls to
+     * objects gained from this method will continue to operate on the original process.
+     *
+     * @param busname    The bus name to connect to. Usually a well known bus name in dot-notation (such as "org.freedesktop.local")
+     *                   or may be a DBus address such as ":1-16".
+     * @param objectpath The path on which the process is exporting the object.$
+     * @param type       The interface they are exporting it on. This type must have the same full class name and exposed method signatures
+     *                   as the interface the remote object is exporting.
+     * @param autostart  Disable/Enable auto-starting of services in response to calls on this object.
+     *                   Default is enabled; when calling a method with auto-start enabled, if the destination is a well-known name
+     *                   and is not owned the bus will attempt to start a process to take the name. When disabled an error is
+     *                   returned immediately.
+     * @return A reference to a remote object.
+     * @throws ClassCastException If type is not a sub-type of DBusInterface
+     * @throws DBusException      If busname or objectpath are incorrectly formatted or type is not in a package.
+     */
+    public <I extends DBusInterface> I getPeerRemoteObject(String busname, String objectpath, Class<I> type, boolean autostart) throws DBusException {
+        if (null == busname) throw new DBusException(getString("nullBusName"));
+
+        if ((!busname.matches(BUSNAME_REGEX) && !busname.matches(CONNID_REGEX))
+                || busname.length() > MAX_NAME_LENGTH)
+            throw new DBusException(getString("invalidBusName") + busname);
+
+        String unique = _dbus.GetNameOwner(busname);
+
+        return getRemoteObject(unique, objectpath, type, autostart);
+    }
+
+    /**
+     * Return a reference to a remote object.
+     * This method will always refer to the well known name (if given) rather than resolving it to a unique bus name.
+     * In particular this means that if a process providing the well known name disappears and is taken over by another process
+     * proxy objects gained by this method will make calls on the new proccess.
+     *
+     * @param busname    The bus name to connect to. Usually a well known bus name name in dot-notation (such as "org.freedesktop.local")
+     *                   or may be a DBus address such as ":1-16".
+     * @param objectpath The path on which the process is exporting the object.
+     * @param type       The interface they are exporting it on. This type must have the same full class name and exposed method signatures
+     *                   as the interface the remote object is exporting.
+     * @return A reference to a remote object.
+     * @throws ClassCastException If type is not a sub-type of DBusInterface
+     * @throws DBusException      If busname or objectpath are incorrectly formatted or type is not in a package.
+     */
+    public <I extends DBusInterface> I getRemoteObject(String busname, String objectpath, Class<I> type) throws DBusException {
+        return getRemoteObject(busname, objectpath, type, true);
+    }
+
+    /**
+     * Return a reference to a remote object.
+     * This method will always refer to the well known name (if given) rather than resolving it to a unique bus name.
+     * In particular this means that if a process providing the well known name disappears and is taken over by another process
+     * proxy objects gained by this method will make calls on the new proccess.
+     *
+     * @param busname    The bus name to connect to. Usually a well known bus name name in dot-notation (such as "org.freedesktop.local")
+     *                   or may be a DBus address such as ":1-16".
+     * @param objectpath The path on which the process is exporting the object.
+     * @param type       The interface they are exporting it on. This type must have the same full class name and exposed method signatures
+     *                   as the interface the remote object is exporting.
+     * @param autostart  Disable/Enable auto-starting of services in response to calls on this object.
+     *                   Default is enabled; when calling a method with auto-start enabled, if the destination is a well-known name
+     *                   and is not owned the bus will attempt to start a process to take the name. When disabled an error is
+     *                   returned immediately.
+     * @return A reference to a remote object.
+     * @throws ClassCastException If type is not a sub-type of DBusInterface
+     * @throws DBusException      If busname or objectpath are incorrectly formatted or type is not in a package.
+     */
+    @SuppressWarnings("unchecked")
+    public <I extends DBusInterface> I getRemoteObject(String busname, String objectpath, Class<I> type, boolean autostart) throws DBusException {
+        if (null == busname) throw new DBusException(getString("nullBusName"));
+        if (null == objectpath) throw new DBusException(getString("nullObjectPath"));
+        if (null == type) throw new ClassCastException(getString("notDBusInterface"));
+
+        if ((!busname.matches(BUSNAME_REGEX) && !busname.matches(CONNID_REGEX))
+                || busname.length() > MAX_NAME_LENGTH)
+            throw new DBusException(getString("invalidBusName") + busname);
+
+        if (!objectpath.matches(OBJECT_REGEX) || objectpath.length() > MAX_NAME_LENGTH)
+            throw new DBusException(getString("invalidObjectPath") + objectpath);
+
+        if (!DBusInterface.class.isAssignableFrom(type)) throw new ClassCastException(getString("notDBusInterface"));
+
+        // don't let people import things which don't have a
+        // valid D-Bus interface name
+        if (type.getName().equals(type.getSimpleName()))
+            throw new DBusException(getString("interfaceNotAllowedOutsidePackage"));
+
+        RemoteObject ro = new RemoteObject(busname, objectpath, type, autostart);
+        I i = (I) Proxy.newProxyInstance(type.getClassLoader(),
+                new Class[]{type}, new RemoteInvocationHandler(this, ro));
+        importedObjects.put(i, ro);
+        return i;
+    }
+
+    /**
+     * Remove a Signal Handler.
+     * Stops listening for this signal.
+     *
+     * @param type   The signal to watch for.
+     * @param source The source of the signal.
+     * @throws DBusException      If listening for the signal on the bus failed.
+     * @throws ClassCastException If type is not a sub-type of DBusSignal.
+     */
+    public <T extends DBusSignal> void removeSigHandler(Class<T> type, String source, DBusSigHandler<T> handler) throws DBusException {
+        if (!DBusSignal.class.isAssignableFrom(type)) throw new ClassCastException(getString("notDBusSignal"));
+        if (source.matches(BUSNAME_REGEX)) throw new DBusException(getString("cannotWatchSignalsWellKnownBussName"));
+        if (!source.matches(CONNID_REGEX) || source.length() > MAX_NAME_LENGTH)
+            throw new DBusException(getString("invalidBusName") + source);
+        removeSigHandler(new DBusMatchRule(type, source, null), handler);
+    }
+
+    /**
+     * Remove a Signal Handler.
+     * Stops listening for this signal.
+     *
+     * @param type   The signal to watch for.
+     * @param source The source of the signal.
+     * @param object The object emitting the signal.
+     * @throws DBusException      If listening for the signal on the bus failed.
+     * @throws ClassCastException If type is not a sub-type of DBusSignal.
+     */
+    public <T extends DBusSignal> void removeSigHandler(Class<T> type, String source, DBusInterface object, DBusSigHandler<T> handler) throws DBusException {
+        if (!DBusSignal.class.isAssignableFrom(type)) throw new ClassCastException(getString("notDBusSignal"));
+        if (source.matches(BUSNAME_REGEX)) throw new DBusException(getString("cannotWatchSignalsWellKnownBussName"));
+        if (!source.matches(CONNID_REGEX) || source.length() > MAX_NAME_LENGTH)
+            throw new DBusException(getString("invalidBusName") + source);
+        String objectpath = importedObjects.get(object).objectpath;
+        if (!objectpath.matches(OBJECT_REGEX) || objectpath.length() > MAX_NAME_LENGTH)
+            throw new DBusException(getString("invalidObjectPath") + objectpath);
+        removeSigHandler(new DBusMatchRule(type, source, objectpath), handler);
+    }
+
+    protected <T extends DBusSignal> void removeSigHandler(DBusMatchRule rule, DBusSigHandler<T> handler) throws DBusException {
+
+        SignalTuple key = new SignalTuple(rule.getInterface(), rule.getMember(), rule.getObject(), rule.getSource());
+        synchronized (handledSignals) {
+            Vector<DBusSigHandler<? extends DBusSignal>> v = handledSignals.get(key);
+            if (null != v) {
+                v.remove(handler);
+                if (0 == v.size()) {
+                    handledSignals.remove(key);
+                    try {
+                        _dbus.RemoveMatch(rule.toString());
+                    } catch (NotConnected NC) {
+                        if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, NC);
+                    } catch (DBusExecutionException DBEe) {
+                        if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBEe);
+                        throw new DBusException(DBEe.getMessage());
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Add a Signal Handler.
+     * Adds a signal handler to call when a signal is received which matches the specified type, name and source.
+     *
+     * @param type    The signal to watch for.
+     * @param source  The process which will send the signal. This <b>MUST</b> be a unique bus name and not a well known name.
+     * @param handler The handler to call when a signal is received.
+     * @throws DBusException      If listening for the signal on the bus failed.
+     * @throws ClassCastException If type is not a sub-type of DBusSignal.
+     */
+    @SuppressWarnings("unchecked")
+    public <T extends DBusSignal> void addSigHandler(Class<T> type, String source, DBusSigHandler<T> handler) throws DBusException {
+        if (!DBusSignal.class.isAssignableFrom(type)) throw new ClassCastException(getString("notDBusSignal"));
+        if (source.matches(BUSNAME_REGEX)) throw new DBusException(getString("cannotWatchSignalsWellKnownBussName"));
+        if (!source.matches(CONNID_REGEX) || source.length() > MAX_NAME_LENGTH)
+            throw new DBusException(getString("invalidBusName") + source);
+        addSigHandler(new DBusMatchRule(type, source, null), (DBusSigHandler<? extends DBusSignal>) handler);
+    }
+
+    /**
+     * Add a Signal Handler.
+     * Adds a signal handler to call when a signal is received which matches the specified type, name, source and object.
+     *
+     * @param type    The signal to watch for.
+     * @param source  The process which will send the signal. This <b>MUST</b> be a unique bus name and not a well known name.
+     * @param object  The object from which the signal will be emitted
+     * @param handler The handler to call when a signal is received.
+     * @throws DBusException      If listening for the signal on the bus failed.
+     * @throws ClassCastException If type is not a sub-type of DBusSignal.
+     */
+    @SuppressWarnings("unchecked")
+    public <T extends DBusSignal> void addSigHandler(Class<T> type, String source, DBusInterface object, DBusSigHandler<T> handler) throws DBusException {
+        if (!DBusSignal.class.isAssignableFrom(type)) throw new ClassCastException(getString("notDBusSignal"));
+        if (source.matches(BUSNAME_REGEX)) throw new DBusException(getString("cannotWatchSignalsWellKnownBussName"));
+        if (!source.matches(CONNID_REGEX) || source.length() > MAX_NAME_LENGTH)
+            throw new DBusException(getString("invalidBusName") + source);
+        String objectpath = importedObjects.get(object).objectpath;
+        if (!objectpath.matches(OBJECT_REGEX) || objectpath.length() > MAX_NAME_LENGTH)
+            throw new DBusException(getString("invalidObjectPath") + objectpath);
+        addSigHandler(new DBusMatchRule(type, source, objectpath), (DBusSigHandler<? extends DBusSignal>) handler);
+    }
+
+    protected <T extends DBusSignal> void addSigHandler(DBusMatchRule rule, DBusSigHandler<T> handler) throws DBusException {
+        try {
+            _dbus.AddMatch(rule.toString());
+        } catch (DBusExecutionException DBEe) {
+            if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBEe);
+            throw new DBusException(DBEe.getMessage());
+        }
+        SignalTuple key = new SignalTuple(rule.getInterface(), rule.getMember(), rule.getObject(), rule.getSource());
+        synchronized (handledSignals) {
+            Vector<DBusSigHandler<? extends DBusSignal>> v = handledSignals.get(key);
+            if (null == v) {
+                v = new Vector<DBusSigHandler<? extends DBusSignal>>();
+                v.add(handler);
+                handledSignals.put(key, v);
+            } else
+                v.add(handler);
+        }
+    }
+
+    /**
+     * Disconnect from the Bus.
+     * This only disconnects when the last reference to the bus has disconnect called on it
+     * or has been destroyed.
+     */
+    public void disconnect() {
+        synchronized (conn) {
+            synchronized (_reflock) {
+                if (0 == --_refcount) {
+                    if (Debug.debug) Debug.print(Debug.INFO, "Disconnecting DBusConnection");
+                    // Set all pending messages to have an error.
+                    try {
+                        Error err = new Error(
+                                "org.freedesktop.DBus.Local", "org.freedesktop.DBus.Local.disconnected", 0, "s", new Object[]{getString("disconnected")});
+                        synchronized (pendingCalls) {
+                            long[] set = pendingCalls.getKeys();
+                            for (long l : set)
+                                if (-1 != l) {
+                                    MethodCall m = pendingCalls.remove(l);
+                                    if (null != m)
+                                        m.setReply(err);
+                                }
+                            pendingCalls = null;
+                        }
+                        synchronized (pendingErrors) {
+                            pendingErrors.add(err);
+                        }
+                    } catch (DBusException DBe) {
+                    }
+
+                    conn.remove(addr);
+                    super.disconnect();
+                }
+            }
+        }
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/DBusInterface.java b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusInterface.java
new file mode 100644
index 0000000..b9e404c
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusInterface.java
@@ -0,0 +1,31 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+/**
+ * Denotes a class as exportable or a remote interface which can be called.
+ * <p>
+ * Any interface which should be exported or imported should extend this
+ * interface. All public methods from that interface are exported/imported
+ * with the given method signatures.
+ * </p>
+ * <p>
+ * All method calls on exported objects are run in their own threads.
+ * Application writers are responsible for any concurrency issues.
+ * </p>
+ */
+public interface DBusInterface {
+    /**
+     * Returns true on remote objects.
+     * Local objects implementing this interface MUST return false.
+     */
+    public boolean isRemote();
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/DBusInterfaceName.java b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusInterfaceName.java
new file mode 100644
index 0000000..0fc7056
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusInterfaceName.java
@@ -0,0 +1,28 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Force the interface name to be different to the Java class name.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface DBusInterfaceName {
+    /**
+     * The replacement interface name.
+     */
+    String value();
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/DBusMap.java b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusMap.java
new file mode 100644
index 0000000..6590e62
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusMap.java
@@ -0,0 +1,150 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.Vector;
+
+class DBusMap<K, V> implements Map<K, V> {
+    Object[][] entries;
+
+    public DBusMap(Object[][] entries) {
+        this.entries = entries;
+    }
+
+    class Entry implements Map.Entry<K, V>, Comparable<Entry> {
+        private int entry;
+
+        public Entry(int i) {
+            this.entry = i;
+        }
+
+        public boolean equals(Object o) {
+            if (null == o) return false;
+            if (!(o instanceof DBusMap.Entry)) return false;
+            return this.entry == ((Entry) o).entry;
+        }
+
+        @SuppressWarnings("unchecked")
+        public K getKey() {
+            return (K) entries[entry][0];
+        }
+
+        @SuppressWarnings("unchecked")
+        public V getValue() {
+            return (V) entries[entry][1];
+        }
+
+        public int hashCode() {
+            return entries[entry][0].hashCode();
+        }
+
+        public V setValue(V value) {
+            throw new UnsupportedOperationException();
+        }
+
+        public int compareTo(Entry e) {
+            return entry - e.entry;
+        }
+    }
+
+    public void clear() {
+        throw new UnsupportedOperationException();
+    }
+
+    public boolean containsKey(Object key) {
+        for (int i = 0; i < entries.length; i++)
+            if (key == entries[i][0] || (key != null && key.equals(entries[i][0])))
+                return true;
+        return false;
+    }
+
+    public boolean containsValue(Object value) {
+        for (int i = 0; i < entries.length; i++)
+            if (value == entries[i][1] || (value != null && value.equals(entries[i][1])))
+                return true;
+        return false;
+    }
+
+    public Set<Map.Entry<K, V>> entrySet() {
+        Set<Map.Entry<K, V>> s = new TreeSet<Map.Entry<K, V>>();
+        for (int i = 0; i < entries.length; i++)
+            s.add(new Entry(i));
+        return s;
+    }
+
+    @SuppressWarnings("unchecked")
+    public V get(Object key) {
+        for (int i = 0; i < entries.length; i++)
+            if (key == entries[i][0] || (key != null && key.equals(entries[i][0])))
+                return (V) entries[i][1];
+        return null;
+    }
+
+    public boolean isEmpty() {
+        return entries.length == 0;
+    }
+
+    @SuppressWarnings("unchecked")
+    public Set<K> keySet() {
+        Set<K> s = new TreeSet<K>();
+        for (Object[] entry : entries)
+            s.add((K) entry[0]);
+        return s;
+    }
+
+    public V put(K key, V value) {
+        throw new UnsupportedOperationException();
+    }
+
+    public void putAll(Map<? extends K, ? extends V> t) {
+        throw new UnsupportedOperationException();
+    }
+
+    public V remove(Object key) {
+        throw new UnsupportedOperationException();
+    }
+
+    public int size() {
+        return entries.length;
+    }
+
+    @SuppressWarnings("unchecked")
+    public Collection<V> values() {
+        List<V> l = new Vector<V>();
+        for (Object[] entry : entries)
+            l.add((V) entry[1]);
+        return l;
+    }
+
+    public int hashCode() {
+        return Arrays.deepHashCode(entries);
+    }
+
+    @SuppressWarnings("unchecked")
+    public boolean equals(Object o) {
+        if (null == o) return false;
+        if (!(o instanceof Map)) return false;
+        return ((Map<K, V>) o).entrySet().equals(entrySet());
+    }
+
+    public String toString() {
+        String s = "{ ";
+        for (int i = 0; i < entries.length; i++)
+            s += entries[i][0] + " => " + entries[i][1] + ",";
+        return s.replaceAll(".$", " }");
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/DBusMatchRule.java b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusMatchRule.java
new file mode 100644
index 0000000..fa886c0
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusMatchRule.java
@@ -0,0 +1,151 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.dbus.exceptions.DBusException;
+import org.freedesktop.dbus.exceptions.DBusExecutionException;
+
+import java.util.HashMap;
+
+import static org.freedesktop.dbus.Gettext.getString;
+
+public class DBusMatchRule {
+    /* signal, error, method_call, method_reply */
+    private String type;
+    private String iface;
+    private String member;
+    private String object;
+    private String source;
+    private static HashMap<String, Class<? extends DBusSignal>> signalTypeMap =
+            new HashMap<String, Class<? extends DBusSignal>>();
+
+    static Class<? extends DBusSignal> getCachedSignalType(String type) {
+        return signalTypeMap.get(type);
+    }
+
+    public DBusMatchRule(String type, String iface, String member) {
+        this.type = type;
+        this.iface = iface;
+        this.member = member;
+    }
+
+    public DBusMatchRule(DBusExecutionException e) throws DBusException {
+        this(e.getClass());
+        member = null;
+        type = "error";
+    }
+
+    public DBusMatchRule(Message m) {
+        iface = m.getInterface();
+        member = m.getName();
+        if (m instanceof DBusSignal)
+            type = "signal";
+        else if (m instanceof Error) {
+            type = "error";
+            member = null;
+        } else if (m instanceof MethodCall)
+            type = "method_call";
+        else if (m instanceof MethodReturn)
+            type = "method_reply";
+    }
+
+    public DBusMatchRule(Class<? extends DBusInterface> c, String method) throws DBusException {
+        this(c);
+        member = method;
+        type = "method_call";
+    }
+
+    public DBusMatchRule(Class<? extends Object> c, String source, String object) throws DBusException {
+        this(c);
+        this.source = source;
+        this.object = object;
+    }
+
+    @SuppressWarnings("unchecked")
+    public DBusMatchRule(Class<? extends Object> c) throws DBusException {
+        if (DBusInterface.class.isAssignableFrom(c)) {
+            if (null != c.getAnnotation(DBusInterfaceName.class))
+                iface = c.getAnnotation(DBusInterfaceName.class).value();
+            else
+                iface = AbstractConnection.dollar_pattern.matcher(c.getName()).replaceAll(".");
+            if (!iface.matches(".*\\..*"))
+                throw new DBusException(getString("interfaceMustBeDefinedPackage"));
+            member = null;
+            type = null;
+        } else if (DBusSignal.class.isAssignableFrom(c)) {
+            if (null == c.getEnclosingClass())
+                throw new DBusException(getString("signalsMustBeMemberOfClass"));
+            else if (null != c.getEnclosingClass().getAnnotation(DBusInterfaceName.class))
+                iface = c.getEnclosingClass().getAnnotation(DBusInterfaceName.class).value();
+            else
+                iface = AbstractConnection.dollar_pattern.matcher(c.getEnclosingClass().getName()).replaceAll(".");
+            // Don't export things which are invalid D-Bus interfaces
+            if (!iface.matches(".*\\..*"))
+                throw new DBusException(getString("interfaceMustBeDefinedPackage"));
+            if (c.isAnnotationPresent(DBusMemberName.class))
+                member = c.getAnnotation(DBusMemberName.class).value();
+            else
+                member = c.getSimpleName();
+            signalTypeMap.put(iface + '$' + member, (Class<? extends DBusSignal>) c);
+            type = "signal";
+        } else if (Error.class.isAssignableFrom(c)) {
+            if (null != c.getAnnotation(DBusInterfaceName.class))
+                iface = c.getAnnotation(DBusInterfaceName.class).value();
+            else
+                iface = AbstractConnection.dollar_pattern.matcher(c.getName()).replaceAll(".");
+            if (!iface.matches(".*\\..*"))
+                throw new DBusException(getString("interfaceMustBeDefinedPackage"));
+            member = null;
+            type = "error";
+        } else if (DBusExecutionException.class.isAssignableFrom(c)) {
+            if (null != c.getClass().getAnnotation(DBusInterfaceName.class))
+                iface = c.getClass().getAnnotation(DBusInterfaceName.class).value();
+            else
+                iface = AbstractConnection.dollar_pattern.matcher(c.getClass().getName()).replaceAll(".");
+            if (!iface.matches(".*\\..*"))
+                throw new DBusException(getString("interfaceMustBeDefinedPackage"));
+            member = null;
+            type = "error";
+        } else
+            throw new DBusException(getString("invalidTypeMatchRule") + c);
+    }
+
+    public String toString() {
+        String s = null;
+        if (null != type) s = null == s ? "type='" + type + "'" : s + ",type='" + type + "'";
+        if (null != member) s = null == s ? "member='" + member + "'" : s + ",member='" + member + "'";
+        if (null != iface) s = null == s ? "interface='" + iface + "'" : s + ",interface='" + iface + "'";
+        if (null != source) s = null == s ? "sender='" + source + "'" : s + ",sender='" + source + "'";
+        if (null != object) s = null == s ? "path='" + object + "'" : s + ",path='" + object + "'";
+        return s;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public String getInterface() {
+        return iface;
+    }
+
+    public String getMember() {
+        return member;
+    }
+
+    public String getSource() {
+        return source;
+    }
+
+    public String getObject() {
+        return object;
+    }
+
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/DBusMemberName.java b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusMemberName.java
new file mode 100644
index 0000000..25d30d7
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusMemberName.java
@@ -0,0 +1,29 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Force the member (method/signal) name on the bus to be different to the Java name.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE, ElementType.METHOD})
+public @interface DBusMemberName {
+    /**
+     * The replacement member name.
+     */
+    String value();
+}
+
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/DBusSerializable.java b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusSerializable.java
new file mode 100644
index 0000000..8d9fea5
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusSerializable.java
@@ -0,0 +1,39 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.dbus.exceptions.DBusException;
+
+/**
+ * Custom classes may be sent over DBus if they implement this interface.
+ * <p>
+ * In addition to the serialize method, classes <b>MUST</b> implement
+ * a deserialize method which returns null and takes as it's arguments
+ * all the DBus types the class will be serialied to <i>in order</i> and
+ * <i>with type parameterisation</i>. They <b>MUST</b> also provide a
+ * zero-argument constructor.
+ * </p>
+ * <p>
+ * The serialize method should return the class properties you wish to
+ * serialize, correctly formatted for the wire
+ * (DBusConnection.convertParameters() can help with this), in order in an
+ * Object array.
+ * </p>
+ * <p>
+ * The deserialize method will be called once after the zero-argument
+ * constructor. This should contain all the code to initialise the object
+ * from the types.
+ * </p>
+ */
+public interface DBusSerializable {
+    public Object[] serialize() throws DBusException;
+}
+            
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/DBusSigHandler.java b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusSigHandler.java
new file mode 100644
index 0000000..6e40a82
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusSigHandler.java
@@ -0,0 +1,27 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+/**
+ * Handle a signal on DBus.
+ * All Signal handlers are run in their own Thread.
+ * Application writers are responsible for managing any concurrency issues.
+ */
+public interface DBusSigHandler<T extends DBusSignal> {
+    /**
+     * Handle a signal.
+     *
+     * @param s The signal to handle. If such a class exists, the
+     *          signal will be an instance of the class with the correct type signature.
+     *          Otherwise it will be an instance of DBusSignal
+     */
+    public void handle(T s);
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/DBusSignal.java b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusSignal.java
new file mode 100644
index 0000000..96ba6b3
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusSignal.java
@@ -0,0 +1,259 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import cx.ath.matthew.debug.Debug;
+import org.freedesktop.dbus.exceptions.DBusException;
+import org.freedesktop.dbus.exceptions.MessageFormatException;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.GenericDeclaration;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Vector;
+
+import static org.freedesktop.dbus.Gettext.getString;
+
+public class DBusSignal extends Message {
+    DBusSignal() {
+    }
+
+    public DBusSignal(String source, String path, String iface, String member, String sig, Object... args) throws DBusException {
+        super(Message.Endian.BIG, Message.MessageType.SIGNAL, (byte) 0);
+
+        if (null == path || null == member || null == iface)
+            throw new MessageFormatException(getString("missingPathInterfaceSignal"));
+        headers.put(Message.HeaderField.PATH, path);
+        headers.put(Message.HeaderField.MEMBER, member);
+        headers.put(Message.HeaderField.INTERFACE, iface);
+
+        Vector<Object> hargs = new Vector<Object>();
+        hargs.add(new Object[]{Message.HeaderField.PATH, new Object[]{ArgumentType.OBJECT_PATH_STRING, path}});
+        hargs.add(new Object[]{Message.HeaderField.INTERFACE, new Object[]{ArgumentType.STRING_STRING, iface}});
+        hargs.add(new Object[]{Message.HeaderField.MEMBER, new Object[]{ArgumentType.STRING_STRING, member}});
+
+        if (null != source) {
+            headers.put(Message.HeaderField.SENDER, source);
+            hargs.add(new Object[]{Message.HeaderField.SENDER, new Object[]{ArgumentType.STRING_STRING, source}});
+        }
+
+        if (null != sig) {
+            hargs.add(new Object[]{Message.HeaderField.SIGNATURE, new Object[]{ArgumentType.SIGNATURE_STRING, sig}});
+            headers.put(Message.HeaderField.SIGNATURE, sig);
+            setArgs(args);
+        }
+
+        blen = new byte[4];
+        appendBytes(blen);
+        append("ua(yv)", ++serial, hargs.toArray());
+        pad((byte) 8);
+
+        long c = bytecounter;
+        if (null != sig) append(sig, args);
+        marshallint(bytecounter - c, blen, 0, 4);
+        bodydone = true;
+    }
+
+    static class internalsig extends DBusSignal {
+        public internalsig(String source, String objectpath, String type, String name, String sig, Object[] parameters, long serial) throws DBusException {
+            super(source, objectpath, type, name, sig, parameters, serial);
+        }
+    }
+
+    private static Map<Class<? extends DBusSignal>, Type[]> typeCache = new HashMap<Class<? extends DBusSignal>, Type[]>();
+    private static Map<String, Class<? extends DBusSignal>> classCache = new HashMap<String, Class<? extends DBusSignal>>();
+    private static Map<Class<? extends DBusSignal>, Constructor<? extends DBusSignal>> conCache = new HashMap<Class<? extends DBusSignal>, Constructor<? extends DBusSignal>>();
+    private static Map<String, String> signames = new HashMap<String, String>();
+    private static Map<String, String> intnames = new HashMap<String, String>();
+    private Class<? extends DBusSignal> c;
+    private boolean bodydone = false;
+    private byte[] blen;
+
+    static void addInterfaceMap(String java, String dbus) {
+        intnames.put(dbus, java);
+    }
+
+    static void addSignalMap(String java, String dbus) {
+        signames.put(dbus, java);
+    }
+
+    static DBusSignal createSignal(Class<? extends DBusSignal> c, String source, String objectpath, String sig, long serial, Object... parameters) throws DBusException {
+        String type = "";
+        if (null != c.getEnclosingClass()) {
+            if (null != c.getEnclosingClass().getAnnotation(DBusInterfaceName.class))
+                type = c.getEnclosingClass().getAnnotation(DBusInterfaceName.class).value();
+            else
+                type = AbstractConnection.dollar_pattern.matcher(c.getEnclosingClass().getName()).replaceAll(".");
+
+        } else
+            throw new DBusException(getString("signalsMustBeMemberOfClass"));
+        DBusSignal s = new internalsig(source, objectpath, type, c.getSimpleName(), sig, parameters, serial);
+        s.c = c;
+        return s;
+    }
+
+    @SuppressWarnings("unchecked")
+    private static Class<? extends DBusSignal> createSignalClass(String intname, String signame) throws DBusException {
+        String name = intname + '$' + signame;
+        Class<? extends DBusSignal> c = classCache.get(name);
+        if (null == c) c = DBusMatchRule.getCachedSignalType(name);
+        if (null != c) return c;
+        do {
+            try {
+                c = (Class<? extends DBusSignal>) Class.forName(name);
+            } catch (ClassNotFoundException CNFe) {
+            }
+            name = name.replaceAll("\\.([^\\.]*)$", "\\$$1");
+        } while (null == c && name.matches(".*\\..*"));
+        if (null == c)
+            throw new DBusException(getString("cannotCreateClassFromSignal") + intname + '.' + signame);
+        classCache.put(name, c);
+        return c;
+    }
+
+    @SuppressWarnings("unchecked")
+    DBusSignal createReal(AbstractConnection conn) throws DBusException {
+        String intname = intnames.get(getInterface());
+        String signame = signames.get(getName());
+        if (null == intname) intname = getInterface();
+        if (null == signame) signame = getName();
+        if (null == c)
+            c = createSignalClass(intname, signame);
+        if (Debug.debug) Debug.print(Debug.DEBUG, "Converting signal to type: " + c);
+        Type[] types = typeCache.get(c);
+        Constructor<? extends DBusSignal> con = conCache.get(c);
+        if (null == types) {
+            con = (Constructor<? extends DBusSignal>) c.getDeclaredConstructors()[0];
+            conCache.put(c, con);
+            Type[] ts = con.getGenericParameterTypes();
+            types = new Type[ts.length - 1];
+            for (int i = 1; i < ts.length; i++)
+                if (ts[i] instanceof TypeVariable)
+                    for (Type b : ((TypeVariable<GenericDeclaration>) ts[i]).getBounds())
+                        types[i - 1] = b;
+                else
+                    types[i - 1] = ts[i];
+            typeCache.put(c, types);
+        }
+
+        try {
+            DBusSignal s;
+            Object[] args = Marshalling.deSerializeParameters(getParameters(), types, conn);
+            if (null == args) s = (DBusSignal) con.newInstance(getPath());
+            else {
+                Object[] params = new Object[args.length + 1];
+                params[0] = getPath();
+                System.arraycopy(args, 0, params, 1, args.length);
+
+                if (Debug.debug)
+                    Debug.print(Debug.DEBUG, "Creating signal of type " + c + " with parameters " + Arrays.deepToString(params));
+                s = (DBusSignal) con.newInstance(params);
+            }
+            s.headers = headers;
+            s.wiredata = wiredata;
+            s.bytecounter = wiredata.length;
+            return s;
+        } catch (Exception e) {
+            if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
+            throw new DBusException(e.getMessage());
+        }
+    }
+
+    /**
+     * Create a new signal.
+     * This contructor MUST be called by all sub classes.
+     *
+     * @param objectpath The path to the object this is emitted from.
+     * @param args       The parameters of the signal.
+     * @throws DBusException This is thrown if the subclass is incorrectly defined.
+     */
+    @SuppressWarnings("unchecked")
+    protected DBusSignal(String objectpath, Object... args) throws DBusException {
+        super(Message.Endian.BIG, Message.MessageType.SIGNAL, (byte) 0);
+
+        if (!objectpath.matches(AbstractConnection.OBJECT_REGEX))
+            throw new DBusException(getString("invalidObjectPath") + objectpath);
+
+        Class<? extends DBusSignal> tc = getClass();
+        String member;
+        if (tc.isAnnotationPresent(DBusMemberName.class))
+            member = tc.getAnnotation(DBusMemberName.class).value();
+        else
+            member = tc.getSimpleName();
+        String iface = null;
+        Class<? extends Object> enc = tc.getEnclosingClass();
+        if (null == enc ||
+                !DBusInterface.class.isAssignableFrom(enc) ||
+                enc.getName().equals(enc.getSimpleName()))
+            throw new DBusException(getString("signalsMustBeMemberOfClass"));
+        else if (null != enc.getAnnotation(DBusInterfaceName.class))
+            iface = enc.getAnnotation(DBusInterfaceName.class).value();
+        else
+            iface = AbstractConnection.dollar_pattern.matcher(enc.getName()).replaceAll(".");
+
+        headers.put(Message.HeaderField.PATH, objectpath);
+        headers.put(Message.HeaderField.MEMBER, member);
+        headers.put(Message.HeaderField.INTERFACE, iface);
+
+        Vector<Object> hargs = new Vector<Object>();
+        hargs.add(new Object[]{Message.HeaderField.PATH, new Object[]{ArgumentType.OBJECT_PATH_STRING, objectpath}});
+        hargs.add(new Object[]{Message.HeaderField.INTERFACE, new Object[]{ArgumentType.STRING_STRING, iface}});
+        hargs.add(new Object[]{Message.HeaderField.MEMBER, new Object[]{ArgumentType.STRING_STRING, member}});
+
+        String sig = null;
+        if (0 < args.length) {
+            try {
+                Type[] types = typeCache.get(tc);
+                if (null == types) {
+                    Constructor<? extends DBusSignal> con = (Constructor<? extends DBusSignal>) tc.getDeclaredConstructors()[0];
+                    conCache.put(tc, con);
+                    Type[] ts = con.getGenericParameterTypes();
+                    types = new Type[ts.length - 1];
+                    for (int i = 1; i <= types.length; i++)
+                        if (ts[i] instanceof TypeVariable)
+                            types[i - 1] = ((TypeVariable<GenericDeclaration>) ts[i]).getBounds()[0];
+                        else
+                            types[i - 1] = ts[i];
+                    typeCache.put(tc, types);
+                }
+                sig = Marshalling.getDBusType(types);
+                hargs.add(new Object[]{Message.HeaderField.SIGNATURE, new Object[]{ArgumentType.SIGNATURE_STRING, sig}});
+                headers.put(Message.HeaderField.SIGNATURE, sig);
+                setArgs(args);
+            } catch (Exception e) {
+                if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
+                throw new DBusException(getString("errorAddSignalParameters") + e.getMessage());
+            }
+        }
+
+        blen = new byte[4];
+        appendBytes(blen);
+        append("ua(yv)", ++serial, hargs.toArray());
+        pad((byte) 8);
+    }
+
+    void appendbody(AbstractConnection conn) throws DBusException {
+        if (bodydone) return;
+
+        Type[] types = typeCache.get(getClass());
+        Object[] args = Marshalling.convertParameters(getParameters(), types, conn);
+        setArgs(args);
+        String sig = getSig();
+
+        long c = bytecounter;
+        if (null != args && 0 < args.length) append(sig, args);
+        marshallint(bytecounter - c, blen, 0, 4);
+        bodydone = true;
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/EfficientMap.java b/federation/sssd/src/main/java/org/freedesktop/dbus/EfficientMap.java
new file mode 100644
index 0000000..32cc7bb
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/EfficientMap.java
@@ -0,0 +1,122 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+/**
+ * Provides a long => MethodCall map which doesn't allocate objects
+ * on insertion/removal. Keys must be inserted in ascending order.
+ */
+class EfficientMap {
+    private long[] kv;
+    private MethodCall[] vv;
+    private int start;
+    private int end;
+    private int init_size;
+
+    public EfficientMap(int initial_size) {
+        init_size = initial_size;
+        shrink();
+    }
+
+    private void grow() {
+        // create new vectors twice as long
+        long[] oldkv = kv;
+        kv = new long[oldkv.length * 2];
+        MethodCall[] oldvv = vv;
+        vv = new MethodCall[oldvv.length * 2];
+
+        // copy start->length to the start of the new vector
+        System.arraycopy(oldkv, start, kv, 0, oldkv.length - start);
+        System.arraycopy(oldvv, start, vv, 0, oldvv.length - start);
+        // copy 0->end to the next part of the new vector
+        if (end != (oldkv.length - 1)) {
+            System.arraycopy(oldkv, 0, kv, oldkv.length - start, end + 1);
+            System.arraycopy(oldvv, 0, vv, oldvv.length - start, end + 1);
+        }
+        // reposition pointers
+        start = 0;
+        end = oldkv.length;
+    }
+
+    // create a new vector with just the valid keys in and return it
+    public long[] getKeys() {
+        int size;
+        if (start < end) size = end - start;
+        else size = kv.length - (start - end);
+        long[] lv = new long[size];
+        int copya;
+        if (size > kv.length - start) copya = kv.length - start;
+        else copya = size;
+        System.arraycopy(kv, start, lv, 0, copya);
+        if (copya < size) {
+            System.arraycopy(kv, 0, lv, copya, size - copya);
+        }
+        return lv;
+    }
+
+    private void shrink() {
+        if (null != kv && kv.length == init_size) return;
+        // reset to original size
+        kv = new long[init_size];
+        vv = new MethodCall[init_size];
+        start = 0;
+        end = 0;
+    }
+
+    public void put(long l, MethodCall m) {
+        // put this at the end
+        kv[end] = l;
+        vv[end] = m;
+        // move the end
+        if (end == (kv.length - 1)) end = 0;
+        else end++;
+        // if we are out of space, grow.
+        if (end == start) grow();
+    }
+
+    public MethodCall remove(long l) {
+        // find the item
+        int pos = find(l);
+        // if we don't have it return null
+        if (-1 == pos) return null;
+        // get the value
+        MethodCall m = vv[pos];
+        // set it as unused
+        vv[pos] = null;
+        kv[pos] = -1;
+        // move the pointer to the first full element
+        while (-1 == kv[start]) {
+            if (start == (kv.length - 1)) start = 0;
+            else start++;
+            // if we have emptied the list, shrink it
+            if (start == end) {
+                shrink();
+                break;
+            }
+        }
+        return m;
+    }
+
+    public boolean contains(long l) {
+        // check if find succeeds
+        return -1 != find(l);
+    }
+
+    /* could binary search, but it's probably the first one */
+    private int find(long l) {
+        int i = start;
+        while (i != end && kv[i] != l)
+            if (i == (kv.length - 1)) i = 0;
+            else i++;
+        if (i == end) return -1;
+        return i;
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/EfficientQueue.java b/federation/sssd/src/main/java/org/freedesktop/dbus/EfficientQueue.java
new file mode 100644
index 0000000..a60c887
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/EfficientQueue.java
@@ -0,0 +1,109 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import cx.ath.matthew.debug.Debug;
+
+/**
+ * Provides a Message queue which doesn't allocate objects
+ * on insertion/removal.
+ */
+class EfficientQueue {
+    private Message[] mv;
+    private int start;
+    private int end;
+    private int init_size;
+
+    public EfficientQueue(int initial_size) {
+        init_size = initial_size;
+        shrink();
+    }
+
+    private void grow() {
+        if (Debug.debug) Debug.print(Debug.DEBUG, "Growing");
+        // create new vectors twice as long
+        Message[] oldmv = mv;
+        mv = new Message[oldmv.length * 2];
+
+        // copy start->length to the start of the new vector
+        System.arraycopy(oldmv, start, mv, 0, oldmv.length - start);
+        // copy 0->end to the next part of the new vector
+        if (end != (oldmv.length - 1)) {
+            System.arraycopy(oldmv, 0, mv, oldmv.length - start, end + 1);
+        }
+        // reposition pointers
+        start = 0;
+        end = oldmv.length;
+    }
+
+    // create a new vector with just the valid keys in and return it
+    public Message[] getKeys() {
+        if (start == end) return new Message[0];
+        Message[] lv;
+        if (start < end) {
+            int size = end - start;
+            lv = new Message[size];
+            System.arraycopy(mv, start, lv, 0, size);
+        } else {
+            int size = mv.length - start + end;
+            lv = new Message[size];
+            System.arraycopy(mv, start, lv, 0, mv.length - start);
+            System.arraycopy(mv, 0, lv, mv.length - start, end);
+        }
+        return lv;
+    }
+
+    private void shrink() {
+        if (Debug.debug) Debug.print(Debug.DEBUG, "Shrinking");
+        if (null != mv && mv.length == init_size) return;
+        // reset to original size
+        mv = new Message[init_size];
+        start = 0;
+        end = 0;
+    }
+
+    public void add(Message m) {
+        if (Debug.debug) Debug.print(Debug.DEBUG, "Enqueueing Message " + m);
+        // put this at the end
+        mv[end] = m;
+        // move the end
+        if (end == (mv.length - 1)) end = 0;
+        else end++;
+        // if we are out of space, grow.
+        if (end == start) grow();
+    }
+
+    public Message remove() {
+        if (start == end) return null;
+        // find the item
+        int pos = start;
+        // get the value
+        Message m = mv[pos];
+        // set it as unused
+        mv[pos] = null;
+        if (start == (mv.length - 1)) start = 0;
+        else start++;
+        if (Debug.debug) Debug.print(Debug.DEBUG, "Dequeueing " + m);
+        return m;
+    }
+
+    public boolean isEmpty() {
+        // check if find succeeds
+        return start == end;
+    }
+
+    public int size() {
+        if (end >= start)
+            return end - start;
+        else
+            return mv.length - start + end;
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/Error.java b/federation/sssd/src/main/java/org/freedesktop/dbus/Error.java
new file mode 100644
index 0000000..3350e95
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/Error.java
@@ -0,0 +1,144 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import cx.ath.matthew.debug.Debug;
+import org.freedesktop.dbus.exceptions.DBusException;
+import org.freedesktop.dbus.exceptions.DBusExecutionException;
+import org.freedesktop.dbus.exceptions.MessageFormatException;
+import org.freedesktop.dbus.exceptions.NotConnected;
+
+import java.lang.reflect.Constructor;
+import java.util.Vector;
+
+import static org.freedesktop.dbus.Gettext.getString;
+
+/**
+ * Error messages which can be sent over the bus.
+ */
+public class Error extends Message {
+    Error() {
+    }
+
+    public Error(String dest, String errorName, long replyserial, String sig, Object... args) throws DBusException {
+        this(null, dest, errorName, replyserial, sig, args);
+    }
+
+    public Error(String source, String dest, String errorName, long replyserial, String sig, Object... args) throws DBusException {
+        super(Message.Endian.BIG, Message.MessageType.ERROR, (byte) 0);
+
+        if (null == errorName)
+            throw new MessageFormatException(getString("missingErrorName"));
+        headers.put(Message.HeaderField.REPLY_SERIAL, replyserial);
+        headers.put(Message.HeaderField.ERROR_NAME, errorName);
+
+        Vector<Object> hargs = new Vector<Object>();
+        hargs.add(new Object[]{Message.HeaderField.ERROR_NAME, new Object[]{ArgumentType.STRING_STRING, errorName}});
+        hargs.add(new Object[]{Message.HeaderField.REPLY_SERIAL, new Object[]{ArgumentType.UINT32_STRING, replyserial}});
+
+        if (null != source) {
+            headers.put(Message.HeaderField.SENDER, source);
+            hargs.add(new Object[]{Message.HeaderField.SENDER, new Object[]{ArgumentType.STRING_STRING, source}});
+        }
+
+        if (null != dest) {
+            headers.put(Message.HeaderField.DESTINATION, dest);
+            hargs.add(new Object[]{Message.HeaderField.DESTINATION, new Object[]{ArgumentType.STRING_STRING, dest}});
+        }
+
+        if (null != sig) {
+            hargs.add(new Object[]{Message.HeaderField.SIGNATURE, new Object[]{ArgumentType.SIGNATURE_STRING, sig}});
+            headers.put(Message.HeaderField.SIGNATURE, sig);
+            setArgs(args);
+        }
+
+        byte[] blen = new byte[4];
+        appendBytes(blen);
+        append("ua(yv)", serial, hargs.toArray());
+        pad((byte) 8);
+
+        long c = bytecounter;
+        if (null != sig) append(sig, args);
+        marshallint(bytecounter - c, blen, 0, 4);
+    }
+
+    public Error(String source, Message m, Throwable e) throws DBusException {
+        this(source, m.getSource(), AbstractConnection.dollar_pattern.matcher(e.getClass().getName()).replaceAll("."), m.getSerial(), "s", e.getMessage());
+    }
+
+    public Error(Message m, Throwable e) throws DBusException {
+        this(m.getSource(), AbstractConnection.dollar_pattern.matcher(e.getClass().getName()).replaceAll("."), m.getSerial(), "s", e.getMessage());
+    }
+
+    @SuppressWarnings("unchecked")
+    private static Class<? extends DBusExecutionException> createExceptionClass(String name) {
+        if (name == "org.freedesktop.DBus.Local.disconnected") return NotConnected.class;
+        Class<? extends DBusExecutionException> c = null;
+        do {
+            try {
+                c = (Class<? extends org.freedesktop.dbus.exceptions.DBusExecutionException>) Class.forName(name);
+            } catch (ClassNotFoundException CNFe) {
+            }
+            name = name.replaceAll("\\.([^\\.]*)$", "\\$$1");
+        } while (null == c && name.matches(".*\\..*"));
+        return c;
+    }
+
+    /**
+     * Turns this into an exception of the correct type
+     */
+    public DBusExecutionException getException() {
+        try {
+            Class<? extends DBusExecutionException> c = createExceptionClass(getName());
+            if (null == c || !DBusExecutionException.class.isAssignableFrom(c)) c = DBusExecutionException.class;
+            Constructor<? extends DBusExecutionException> con = c.getConstructor(String.class);
+            DBusExecutionException ex;
+            Object[] args = getParameters();
+            if (null == args || 0 == args.length)
+                ex = con.newInstance("");
+            else {
+                String s = "";
+                for (Object o : args)
+                    s += o + " ";
+                ex = con.newInstance(s.trim());
+            }
+            ex.setType(getName());
+            return ex;
+        } catch (Exception e) {
+            if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
+            if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug && null != e.getCause())
+                Debug.print(Debug.ERR, e.getCause());
+            DBusExecutionException ex;
+            Object[] args = null;
+            try {
+                args = getParameters();
+            } catch (Exception ee) {
+            }
+            if (null == args || 0 == args.length)
+                ex = new DBusExecutionException("");
+            else {
+                String s = "";
+                for (Object o : args)
+                    s += o + " ";
+                ex = new DBusExecutionException(s.trim());
+            }
+            ex.setType(getName());
+            return ex;
+        }
+    }
+
+    /**
+     * Throw this as an exception of the correct type
+     */
+    public void throwException() throws DBusExecutionException {
+        throw getException();
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/DBusException.java b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/DBusException.java
new file mode 100644
index 0000000..d9c7e93
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/DBusException.java
@@ -0,0 +1,24 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus.exceptions;
+
+/**
+ * An exception within DBus.
+ */
+@SuppressWarnings("serial")
+public class DBusException extends Exception {
+    /**
+     * Create an exception with the specified message
+     */
+    public DBusException(String message) {
+        super(message);
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/DBusExecutionException.java b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/DBusExecutionException.java
new file mode 100644
index 0000000..641a967
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/DBusExecutionException.java
@@ -0,0 +1,39 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus.exceptions;
+
+/**
+ * An exception while running a remote method within DBus.
+ */
+@SuppressWarnings("serial")
+public class DBusExecutionException extends RuntimeException {
+    private String type;
+
+    /**
+     * Create an exception with the specified message
+     */
+    public DBusExecutionException(String message) {
+        super(message);
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    /**
+     * Get the DBus type of this exception. Use if this
+     * was an exception we don't have a class file for.
+     */
+    public String getType() {
+        if (null == type) return getClass().getName();
+        else return type;
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/FatalDBusException.java b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/FatalDBusException.java
new file mode 100644
index 0000000..90002de
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/FatalDBusException.java
@@ -0,0 +1,18 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus.exceptions;
+
+@SuppressWarnings("serial")
+public class FatalDBusException extends DBusException implements FatalException {
+    public FatalDBusException(String message) {
+        super(message);
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/FatalException.java b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/FatalException.java
new file mode 100644
index 0000000..58e3220
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/FatalException.java
@@ -0,0 +1,14 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus.exceptions;
+
+public interface FatalException {
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/InternalMessageException.java b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/InternalMessageException.java
new file mode 100644
index 0000000..ab9ecc1
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/InternalMessageException.java
@@ -0,0 +1,18 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus.exceptions;
+
+@SuppressWarnings("serial")
+public class InternalMessageException extends DBusExecutionException implements NonFatalException {
+    public InternalMessageException(String message) {
+        super(message);
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/MarshallingException.java b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/MarshallingException.java
new file mode 100644
index 0000000..3635456
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/MarshallingException.java
@@ -0,0 +1,18 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus.exceptions;
+
+@SuppressWarnings("serial")
+public class MarshallingException extends DBusException implements NonFatalException {
+    public MarshallingException(String message) {
+        super(message);
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/MessageFormatException.java b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/MessageFormatException.java
new file mode 100644
index 0000000..e8a1938
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/MessageFormatException.java
@@ -0,0 +1,21 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus.exceptions;
+
+/**
+ * Thrown if a message is formatted incorrectly.
+ */
+@SuppressWarnings("serial")
+public class MessageFormatException extends DBusException implements NonFatalException {
+    public MessageFormatException(String message) {
+        super(message);
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/MessageProtocolVersionException.java b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/MessageProtocolVersionException.java
new file mode 100644
index 0000000..c093b41
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/MessageProtocolVersionException.java
@@ -0,0 +1,20 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus.exceptions;
+
+import java.io.IOException;
+
+@SuppressWarnings("serial")
+public class MessageProtocolVersionException extends IOException implements FatalException {
+    public MessageProtocolVersionException(String message) {
+        super(message);
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/MessageTypeException.java b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/MessageTypeException.java
new file mode 100644
index 0000000..21028e1
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/MessageTypeException.java
@@ -0,0 +1,20 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus.exceptions;
+
+import java.io.IOException;
+
+@SuppressWarnings("serial")
+public class MessageTypeException extends IOException implements NonFatalException {
+    public MessageTypeException(String message) {
+        super(message);
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/NonFatalException.java b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/NonFatalException.java
new file mode 100644
index 0000000..e6a0f36
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/NonFatalException.java
@@ -0,0 +1,14 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus.exceptions;
+
+public interface NonFatalException {
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/NotConnected.java b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/NotConnected.java
new file mode 100644
index 0000000..0610c20
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/NotConnected.java
@@ -0,0 +1,21 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus.exceptions;
+
+/**
+ * Thrown if a DBus action is called when not connected to the Bus.
+ */
+@SuppressWarnings("serial")
+public class NotConnected extends DBusExecutionException implements FatalException {
+    public NotConnected(String message) {
+        super(message);
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/UnknownTypeCodeException.java b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/UnknownTypeCodeException.java
new file mode 100644
index 0000000..af35075
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/UnknownTypeCodeException.java
@@ -0,0 +1,20 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus.exceptions;
+
+import static org.freedesktop.dbus.Gettext.getString;
+
+@SuppressWarnings("serial")
+public class UnknownTypeCodeException extends DBusException implements NonFatalException {
+    public UnknownTypeCodeException(byte code) {
+        super(getString("invalidDBusCode") + code);
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/ExportedObject.java b/federation/sssd/src/main/java/org/freedesktop/dbus/ExportedObject.java
new file mode 100644
index 0000000..b9719a1
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/ExportedObject.java
@@ -0,0 +1,165 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.dbus.exceptions.DBusException;
+import org.freedesktop.dbus.exceptions.DBusExecutionException;
+
+import java.lang.annotation.Annotation;
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.freedesktop.dbus.Gettext.getString;
+
+class ExportedObject {
+    @SuppressWarnings("unchecked")
+    private String getAnnotations(AnnotatedElement c) {
+        String ans = "";
+        for (Annotation a : c.getDeclaredAnnotations()) {
+            Class t = a.annotationType();
+            String value = "";
+            try {
+                Method m = t.getMethod("value");
+                value = m.invoke(a).toString();
+            } catch (NoSuchMethodException NSMe) {
+            } catch (InvocationTargetException ITe) {
+            } catch (IllegalAccessException IAe) {
+            }
+
+            ans += "  <annotation name=\"" + AbstractConnection.dollar_pattern.matcher(t.getName()).replaceAll(".") + "\" value=\"" + value + "\" />\n";
+        }
+        return ans;
+    }
+
+    @SuppressWarnings("unchecked")
+    private Map<MethodTuple, Method> getExportedMethods(Class c) throws DBusException {
+        if (DBusInterface.class.equals(c)) return new HashMap<MethodTuple, Method>();
+        Map<MethodTuple, Method> m = new HashMap<MethodTuple, Method>();
+        for (Class i : c.getInterfaces())
+            if (DBusInterface.class.equals(i)) {
+                // add this class's public methods
+                if (null != c.getAnnotation(DBusInterfaceName.class)) {
+                    String name = ((DBusInterfaceName) c.getAnnotation(DBusInterfaceName.class)).value();
+                    introspectiondata += " <interface name=\"" + name + "\">\n";
+                    DBusSignal.addInterfaceMap(c.getName(), name);
+                } else {
+                    // don't let people export things which don't have a
+                    // valid D-Bus interface name
+                    if (c.getName().equals(c.getSimpleName()))
+                        throw new DBusException(getString("interfaceNotAllowedOutsidePackage"));
+                    if (c.getName().length() > DBusConnection.MAX_NAME_LENGTH)
+                        throw new DBusException(getString("introspectInterfaceExceedCharacters") + c.getName());
+                    else
+                        introspectiondata += " <interface name=\"" + AbstractConnection.dollar_pattern.matcher(c.getName()).replaceAll(".") + "\">\n";
+                }
+                introspectiondata += getAnnotations(c);
+                for (Method meth : c.getDeclaredMethods())
+                    if (Modifier.isPublic(meth.getModifiers())) {
+                        String ms = "";
+                        String name;
+                        if (meth.isAnnotationPresent(DBusMemberName.class))
+                            name = meth.getAnnotation(DBusMemberName.class).value();
+                        else
+                            name = meth.getName();
+                        if (name.length() > DBusConnection.MAX_NAME_LENGTH)
+                            throw new DBusException(getString("introspectMethodExceedCharacters") + name);
+                        introspectiondata += "  <method name=\"" + name + "\" >\n";
+                        introspectiondata += getAnnotations(meth);
+                        for (Class ex : meth.getExceptionTypes())
+                            if (DBusExecutionException.class.isAssignableFrom(ex))
+                                introspectiondata +=
+                                        "   <annotation name=\"org.freedesktop.DBus.Method.Error\" value=\"" + AbstractConnection.dollar_pattern.matcher(ex.getName()).replaceAll(".") + "\" />\n";
+                        for (Type pt : meth.getGenericParameterTypes())
+                            for (String s : Marshalling.getDBusType(pt)) {
+                                introspectiondata += "   <arg type=\"" + s + "\" direction=\"in\"/>\n";
+                                ms += s;
+                            }
+                        if (!Void.TYPE.equals(meth.getGenericReturnType())) {
+                            if (Tuple.class.isAssignableFrom((Class) meth.getReturnType())) {
+                                ParameterizedType tc = (ParameterizedType) meth.getGenericReturnType();
+                                Type[] ts = tc.getActualTypeArguments();
+
+                                for (Type t : ts)
+                                    if (t != null)
+                                        for (String s : Marshalling.getDBusType(t))
+                                            introspectiondata += "   <arg type=\"" + s + "\" direction=\"out\"/>\n";
+                            } else if (Object[].class.equals(meth.getGenericReturnType())) {
+                                throw new DBusException(getString("cannotIntrospectReturnType"));
+                            } else
+                                for (String s : Marshalling.getDBusType(meth.getGenericReturnType()))
+                                    introspectiondata += "   <arg type=\"" + s + "\" direction=\"out\"/>\n";
+                        }
+                        introspectiondata += "  </method>\n";
+                        m.put(new MethodTuple(name, ms), meth);
+                    }
+                for (Class sig : c.getDeclaredClasses())
+                    if (DBusSignal.class.isAssignableFrom(sig)) {
+                        String name;
+                        if (sig.isAnnotationPresent(DBusMemberName.class)) {
+                            name = ((DBusMemberName) sig.getAnnotation(DBusMemberName.class)).value();
+                            DBusSignal.addSignalMap(sig.getSimpleName(), name);
+                        } else
+                            name = sig.getSimpleName();
+                        if (name.length() > DBusConnection.MAX_NAME_LENGTH)
+                            throw new DBusException(getString("introspectSignalExceedCharacters") + name);
+                        introspectiondata += "  <signal name=\"" + name + "\">\n";
+                        Constructor con = sig.getConstructors()[0];
+                        Type[] ts = con.getGenericParameterTypes();
+                        for (int j = 1; j < ts.length; j++)
+                            for (String s : Marshalling.getDBusType(ts[j]))
+                                introspectiondata += "   <arg type=\"" + s + "\" direction=\"out\" />\n";
+                        introspectiondata += getAnnotations(sig);
+                        introspectiondata += "  </signal>\n";
+
+                    }
+                introspectiondata += " </interface>\n";
+            } else {
+                // recurse
+                m.putAll(getExportedMethods(i));
+            }
+        return m;
+    }
+
+    Map<MethodTuple, Method> methods;
+    Reference<DBusInterface> object;
+    String introspectiondata;
+
+    public ExportedObject(DBusInterface object, boolean weakreferences) throws DBusException {
+        if (weakreferences)
+            this.object = new WeakReference<DBusInterface>(object);
+        else
+            this.object = new StrongReference<DBusInterface>(object);
+        introspectiondata = "";
+        methods = getExportedMethods(object.getClass());
+        introspectiondata +=
+                " <interface name=\"org.freedesktop.DBus.Introspectable\">\n" +
+                        "  <method name=\"Introspect\">\n" +
+                        "   <arg type=\"s\" direction=\"out\"/>\n" +
+                        "  </method>\n" +
+                        " </interface>\n";
+        introspectiondata +=
+                " <interface name=\"org.freedesktop.DBus.Peer\">\n" +
+                        "  <method name=\"Ping\">\n" +
+                        "  </method>\n" +
+                        " </interface>\n";
+    }
+}
+
+
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/Gettext.java b/federation/sssd/src/main/java/org/freedesktop/dbus/Gettext.java
new file mode 100644
index 0000000..a519a6f
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/Gettext.java
@@ -0,0 +1,30 @@
+/* 
+ * Pescetti Pseudo-Duplimate Generator
+ * 
+ * Copyright (C) 2007 Matthew Johnson
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License Version 2 as published by
+ * the Free Software Foundation.  This program is distributed in the hope that
+ * it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.  You should have received a
+ * copy of the GNU Lesser General Public License along with this program; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA  02111-1307, USA.
+ *
+ * To Contact me, please email src@matthew.ath.cx
+ *
+ */
+package org.freedesktop.dbus;
+
+import java.util.ResourceBundle;
+
+public class Gettext {
+    private static ResourceBundle myResources =
+            ResourceBundle.getBundle("en_US");
+
+    public static String getString(String s) {
+        return myResources.getString(s);
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/InternalSignal.java b/federation/sssd/src/main/java/org/freedesktop/dbus/InternalSignal.java
new file mode 100644
index 0000000..0a3072d
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/InternalSignal.java
@@ -0,0 +1,20 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.dbus.exceptions.DBusException;
+
+class InternalSignal extends DBusSignal {
+    public InternalSignal(String source, String objectpath, String name, String iface, String sig, long serial, Object... parameters) throws DBusException {
+        super(objectpath, iface, name, sig, parameters);
+        this.serial = serial;
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/Marshalling.java b/federation/sssd/src/main/java/org/freedesktop/dbus/Marshalling.java
new file mode 100644
index 0000000..9e88309
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/Marshalling.java
@@ -0,0 +1,629 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import cx.ath.matthew.debug.Debug;
+import org.freedesktop.dbus.exceptions.DBusException;
+import org.freedesktop.dbus.types.DBusListType;
+import org.freedesktop.dbus.types.DBusMapType;
+import org.freedesktop.dbus.types.DBusStructType;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.text.MessageFormat;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Vector;
+
+import static org.freedesktop.dbus.Gettext.getString;
+
+/**
+ * Contains static methods for marshalling values.
+ */
+public class Marshalling {
+    private static Map<Type, String[]> typeCache = new HashMap<Type, String[]>();
+
+    /**
+     * Will return the DBus type corresponding to the given Java type.
+     * Note, container type should have their ParameterizedType not their
+     * Class passed in here.
+     *
+     * @param c The Java types.
+     * @return The DBus types.
+     * @throws DBusException If the given type cannot be converted to a DBus type.
+     */
+    public static String getDBusType(Type[] c) throws DBusException {
+        StringBuffer sb = new StringBuffer();
+        for (Type t : c)
+            for (String s : getDBusType(t))
+                sb.append(s);
+        return sb.toString();
+    }
+
+    /**
+     * Will return the DBus type corresponding to the given Java type.
+     * Note, container type should have their ParameterizedType not their
+     * Class passed in here.
+     *
+     * @param c The Java type.
+     * @return The DBus type.
+     * @throws DBusException If the given type cannot be converted to a DBus type.
+     */
+    public static String[] getDBusType(Type c) throws DBusException {
+        String[] cached = typeCache.get(c);
+        if (null != cached) return cached;
+        cached = getDBusType(c, false);
+        typeCache.put(c, cached);
+        return cached;
+    }
+
+    /**
+     * Will return the DBus type corresponding to the given Java type.
+     * Note, container type should have their ParameterizedType not their
+     * Class passed in here.
+     *
+     * @param c     The Java type.
+     * @param basic If true enforces this to be a non-compound type. (compound types are Maps, Structs and Lists/arrays).
+     * @return The DBus type.
+     * @throws DBusException If the given type cannot be converted to a DBus type.
+     */
+    public static String[] getDBusType(Type c, boolean basic) throws DBusException {
+        return recursiveGetDBusType(c, basic, 0);
+    }
+
+    private static StringBuffer[] out = new StringBuffer[10];
+
+    @SuppressWarnings("unchecked")
+    public static String[] recursiveGetDBusType(Type c, boolean basic, int level) throws DBusException {
+        if (out.length <= level) {
+            StringBuffer[] newout = new StringBuffer[out.length];
+            System.arraycopy(out, 0, newout, 0, out.length);
+            out = newout;
+        }
+        if (null == out[level]) out[level] = new StringBuffer();
+        else out[level].delete(0, out[level].length());
+
+        if (basic && !(c instanceof Class))
+            throw new DBusException(c + getString("notBasicType"));
+
+        if (c instanceof TypeVariable) out[level].append((char) Message.ArgumentType.VARIANT);
+        else if (c instanceof GenericArrayType) {
+            out[level].append((char) Message.ArgumentType.ARRAY);
+            String[] s = recursiveGetDBusType(((GenericArrayType) c).getGenericComponentType(), false, level + 1);
+            if (s.length != 1) throw new DBusException(getString("multiValuedArrayNotPermitted"));
+            out[level].append(s[0]);
+        } else if ((c instanceof Class &&
+                DBusSerializable.class.isAssignableFrom((Class<? extends Object>) c)) ||
+                (c instanceof ParameterizedType &&
+                        DBusSerializable.class.isAssignableFrom((Class<? extends Object>) ((ParameterizedType) c).getRawType()))) {
+            // it's a custom serializable type
+            Type[] newtypes = null;
+            if (c instanceof Class) {
+                for (Method m : ((Class<? extends Object>) c).getDeclaredMethods())
+                    if (m.getName().equals("deserialize"))
+                        newtypes = m.getGenericParameterTypes();
+            } else
+                for (Method m : ((Class<? extends Object>) ((ParameterizedType) c).getRawType()).getDeclaredMethods())
+                    if (m.getName().equals("deserialize"))
+                        newtypes = m.getGenericParameterTypes();
+
+            if (null == newtypes) throw new DBusException(getString("mustImplementDeserializeMethod"));
+
+            String[] sigs = new String[newtypes.length];
+            for (int j = 0; j < sigs.length; j++) {
+                String[] ss = recursiveGetDBusType(newtypes[j], false, level + 1);
+                if (1 != ss.length) throw new DBusException(getString("mustSerializeNativeDBusTypes"));
+                sigs[j] = ss[0];
+            }
+            return sigs;
+        } else if (c instanceof ParameterizedType) {
+            ParameterizedType p = (ParameterizedType) c;
+            if (p.getRawType().equals(Map.class)) {
+                out[level].append("a{");
+                Type[] t = p.getActualTypeArguments();
+                try {
+                    String[] s = recursiveGetDBusType(t[0], true, level + 1);
+                    if (s.length != 1) throw new DBusException(getString("multiValuedArrayNotPermitted"));
+                    out[level].append(s[0]);
+                    s = recursiveGetDBusType(t[1], false, level + 1);
+                    if (s.length != 1) throw new DBusException(getString("multiValuedArrayNotPermitted"));
+                    out[level].append(s[0]);
+                } catch (ArrayIndexOutOfBoundsException AIOOBe) {
+                    if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, AIOOBe);
+                    throw new DBusException(getString("mapParameters"));
+                }
+                out[level].append('}');
+            } else if (List.class.isAssignableFrom((Class<? extends Object>) p.getRawType())) {
+                for (Type t : p.getActualTypeArguments()) {
+                    if (Type.class.equals(t))
+                        out[level].append((char) Message.ArgumentType.SIGNATURE);
+                    else {
+                        String[] s = recursiveGetDBusType(t, false, level + 1);
+                        if (s.length != 1) throw new DBusException(getString("multiValuedArrayNotPermitted"));
+                        out[level].append((char) Message.ArgumentType.ARRAY);
+                        out[level].append(s[0]);
+                    }
+                }
+            } else if (p.getRawType().equals(Variant.class)) {
+                out[level].append((char) Message.ArgumentType.VARIANT);
+            } else if (DBusInterface.class.isAssignableFrom((Class<? extends Object>) p.getRawType())) {
+                out[level].append((char) Message.ArgumentType.OBJECT_PATH);
+            } else if (Tuple.class.isAssignableFrom((Class<? extends Object>) p.getRawType())) {
+                Type[] ts = p.getActualTypeArguments();
+                Vector<String> vs = new Vector<String>();
+                for (Type t : ts)
+                    for (String s : recursiveGetDBusType(t, false, level + 1))
+                        vs.add(s);
+                return vs.toArray(new String[0]);
+            } else
+                throw new DBusException(getString("nonExportableParameterizedType") + c);
+        } else if (c.equals(Byte.class)) out[level].append((char) Message.ArgumentType.BYTE);
+        else if (c.equals(Byte.TYPE)) out[level].append((char) Message.ArgumentType.BYTE);
+        else if (c.equals(Boolean.class)) out[level].append((char) Message.ArgumentType.BOOLEAN);
+        else if (c.equals(Boolean.TYPE)) out[level].append((char) Message.ArgumentType.BOOLEAN);
+        else if (c.equals(Short.class)) out[level].append((char) Message.ArgumentType.INT16);
+        else if (c.equals(Short.TYPE)) out[level].append((char) Message.ArgumentType.INT16);
+        else if (c.equals(UInt16.class)) out[level].append((char) Message.ArgumentType.UINT16);
+        else if (c.equals(Integer.class)) out[level].append((char) Message.ArgumentType.INT32);
+        else if (c.equals(Integer.TYPE)) out[level].append((char) Message.ArgumentType.INT32);
+        else if (c.equals(UInt32.class)) out[level].append((char) Message.ArgumentType.UINT32);
+        else if (c.equals(Long.class)) out[level].append((char) Message.ArgumentType.INT64);
+        else if (c.equals(Long.TYPE)) out[level].append((char) Message.ArgumentType.INT64);
+        else if (c.equals(UInt64.class)) out[level].append((char) Message.ArgumentType.UINT64);
+        else if (c.equals(Double.class)) out[level].append((char) Message.ArgumentType.DOUBLE);
+        else if (c.equals(Double.TYPE)) out[level].append((char) Message.ArgumentType.DOUBLE);
+        else if (c.equals(Float.class) && AbstractConnection.FLOAT_SUPPORT)
+            out[level].append((char) Message.ArgumentType.FLOAT);
+        else if (c.equals(Float.class)) out[level].append((char) Message.ArgumentType.DOUBLE);
+        else if (c.equals(Float.TYPE) && AbstractConnection.FLOAT_SUPPORT)
+            out[level].append((char) Message.ArgumentType.FLOAT);
+        else if (c.equals(Float.TYPE)) out[level].append((char) Message.ArgumentType.DOUBLE);
+        else if (c.equals(String.class)) out[level].append((char) Message.ArgumentType.STRING);
+        else if (c.equals(Variant.class)) out[level].append((char) Message.ArgumentType.VARIANT);
+        else if (c instanceof Class &&
+                DBusInterface.class.isAssignableFrom((Class<? extends Object>) c))
+            out[level].append((char) Message.ArgumentType.OBJECT_PATH);
+        else if (c instanceof Class &&
+                Path.class.equals((Class<? extends Object>) c))
+            out[level].append((char) Message.ArgumentType.OBJECT_PATH);
+        else if (c instanceof Class &&
+                ObjectPath.class.equals((Class<? extends Object>) c))
+            out[level].append((char) Message.ArgumentType.OBJECT_PATH);
+        else if (c instanceof Class &&
+                ((Class<? extends Object>) c).isArray()) {
+            if (Type.class.equals(((Class<? extends Object>) c).getComponentType()))
+                out[level].append((char) Message.ArgumentType.SIGNATURE);
+            else {
+                out[level].append((char) Message.ArgumentType.ARRAY);
+                String[] s = recursiveGetDBusType(((Class<? extends Object>) c).getComponentType(), false, level + 1);
+                if (s.length != 1) throw new DBusException(getString("multiValuedArrayNotPermitted"));
+                out[level].append(s[0]);
+            }
+        } else if (c instanceof Class &&
+                Struct.class.isAssignableFrom((Class<? extends Object>) c)) {
+            out[level].append((char) Message.ArgumentType.STRUCT1);
+            Type[] ts = Container.getTypeCache(c);
+            if (null == ts) {
+                Field[] fs = ((Class<? extends Object>) c).getDeclaredFields();
+                ts = new Type[fs.length];
+                for (Field f : fs) {
+                    Position p = f.getAnnotation(Position.class);
+                    if (null == p) continue;
+                    ts[p.value()] = f.getGenericType();
+                }
+                Container.putTypeCache(c, ts);
+            }
+
+            for (Type t : ts)
+                if (t != null)
+                    for (String s : recursiveGetDBusType(t, false, level + 1))
+                        out[level].append(s);
+            out[level].append(')');
+        } else {
+            throw new DBusException(getString("nonExportableType") + c);
+        }
+
+        if (Debug.debug) Debug.print(Debug.VERBOSE, "Converted Java type: " + c + " to D-Bus Type: " + out[level]);
+
+        return new String[]{out[level].toString()};
+    }
+
+    /**
+     * Converts a dbus type string into Java Type objects,
+     *
+     * @param dbus  The DBus type or types.
+     * @param rv    Vector to return the types in.
+     * @param limit Maximum number of types to parse (-1 == nolimit).
+     * @return number of characters parsed from the type string.
+     */
+    public static int getJavaType(String dbus, List<Type> rv, int limit) throws DBusException {
+        if (null == dbus || "".equals(dbus) || 0 == limit) return 0;
+
+        try {
+            int i = 0;
+            for (; i < dbus.length() && (-1 == limit || limit > rv.size()); i++)
+                switch (dbus.charAt(i)) {
+                    case Message.ArgumentType.STRUCT1:
+                        int j = i + 1;
+                        for (int c = 1; c > 0; j++) {
+                            if (')' == dbus.charAt(j)) c--;
+                            else if (Message.ArgumentType.STRUCT1 == dbus.charAt(j)) c++;
+                        }
+
+                        Vector<Type> contained = new Vector<Type>();
+                        int c = getJavaType(dbus.substring(i + 1, j - 1), contained, -1);
+                        rv.add(new DBusStructType(contained.toArray(new Type[0])));
+                        i = j;
+                        break;
+                    case Message.ArgumentType.ARRAY:
+                        if (Message.ArgumentType.DICT_ENTRY1 == dbus.charAt(i + 1)) {
+                            contained = new Vector<Type>();
+                            c = getJavaType(dbus.substring(i + 2), contained, 2);
+                            rv.add(new DBusMapType(contained.get(0), contained.get(1)));
+                            i += (c + 2);
+                        } else {
+                            contained = new Vector<Type>();
+                            c = getJavaType(dbus.substring(i + 1), contained, 1);
+                            rv.add(new DBusListType(contained.get(0)));
+                            i += c;
+                        }
+                        break;
+                    case Message.ArgumentType.VARIANT:
+                        rv.add(Variant.class);
+                        break;
+                    case Message.ArgumentType.BOOLEAN:
+                        rv.add(Boolean.class);
+                        break;
+                    case Message.ArgumentType.INT16:
+                        rv.add(Short.class);
+                        break;
+                    case Message.ArgumentType.BYTE:
+                        rv.add(Byte.class);
+                        break;
+                    case Message.ArgumentType.OBJECT_PATH:
+                        rv.add(DBusInterface.class);
+                        break;
+                    case Message.ArgumentType.UINT16:
+                        rv.add(UInt16.class);
+                        break;
+                    case Message.ArgumentType.INT32:
+                        rv.add(Integer.class);
+                        break;
+                    case Message.ArgumentType.UINT32:
+                        rv.add(UInt32.class);
+                        break;
+                    case Message.ArgumentType.INT64:
+                        rv.add(Long.class);
+                        break;
+                    case Message.ArgumentType.UINT64:
+                        rv.add(UInt64.class);
+                        break;
+                    case Message.ArgumentType.DOUBLE:
+                        rv.add(Double.class);
+                        break;
+                    case Message.ArgumentType.FLOAT:
+                        rv.add(Float.class);
+                        break;
+                    case Message.ArgumentType.STRING:
+                        rv.add(String.class);
+                        break;
+                    case Message.ArgumentType.SIGNATURE:
+                        rv.add(Type[].class);
+                        break;
+                    case Message.ArgumentType.DICT_ENTRY1:
+                        rv.add(Map.Entry.class);
+                        contained = new Vector<Type>();
+                        c = getJavaType(dbus.substring(i + 1), contained, 2);
+                        i += c + 1;
+                        break;
+                    default:
+                        throw new DBusException(MessageFormat.format(getString("parseDBusSignatureFailure"), new Object[]{dbus, dbus.charAt(i)}));
+                }
+            return i;
+        } catch (IndexOutOfBoundsException IOOBe) {
+            if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, IOOBe);
+            throw new DBusException(getString("parseDBusTypeSignatureFailure") + dbus);
+        }
+    }
+
+    /**
+     * Recursively converts types for serialization onto DBus.
+     *
+     * @param parameters The parameters to convert.
+     * @param types      The (possibly generic) types of the parameters.
+     * @return The converted parameters.
+     * @throws DBusException Thrown if there is an error in converting the objects.
+     */
+    @SuppressWarnings("unchecked")
+    public static Object[] convertParameters(Object[] parameters, Type[] types, AbstractConnection conn) throws DBusException {
+        if (null == parameters) return null;
+        for (int i = 0; i < parameters.length; i++) {
+            if (Debug.debug)
+                Debug.print(Debug.VERBOSE, "Converting " + i + " from " + parameters[i] + " to " + types[i]);
+            if (null == parameters[i]) continue;
+
+            if (parameters[i] instanceof DBusSerializable) {
+                for (Method m : parameters[i].getClass().getDeclaredMethods())
+                    if (m.getName().equals("deserialize")) {
+                        Type[] newtypes = m.getParameterTypes();
+                        Type[] expand = new Type[types.length + newtypes.length - 1];
+                        System.arraycopy(types, 0, expand, 0, i);
+                        System.arraycopy(newtypes, 0, expand, i, newtypes.length);
+                        System.arraycopy(types, i + 1, expand, i + newtypes.length, types.length - i - 1);
+                        types = expand;
+                        Object[] newparams = ((DBusSerializable) parameters[i]).serialize();
+                        Object[] exparams = new Object[parameters.length + newparams.length - 1];
+                        System.arraycopy(parameters, 0, exparams, 0, i);
+                        System.arraycopy(newparams, 0, exparams, i, newparams.length);
+                        System.arraycopy(parameters, i + 1, exparams, i + newparams.length, parameters.length - i - 1);
+                        parameters = exparams;
+                    }
+                i--;
+            } else if (parameters[i] instanceof Tuple) {
+                Type[] newtypes = ((ParameterizedType) types[i]).getActualTypeArguments();
+                Type[] expand = new Type[types.length + newtypes.length - 1];
+                System.arraycopy(types, 0, expand, 0, i);
+                System.arraycopy(newtypes, 0, expand, i, newtypes.length);
+                System.arraycopy(types, i + 1, expand, i + newtypes.length, types.length - i - 1);
+                types = expand;
+                Object[] newparams = ((Tuple) parameters[i]).getParameters();
+                Object[] exparams = new Object[parameters.length + newparams.length - 1];
+                System.arraycopy(parameters, 0, exparams, 0, i);
+                System.arraycopy(newparams, 0, exparams, i, newparams.length);
+                System.arraycopy(parameters, i + 1, exparams, i + newparams.length, parameters.length - i - 1);
+                parameters = exparams;
+                if (Debug.debug)
+                    Debug.print(Debug.VERBOSE, "New params: " + Arrays.deepToString(parameters) + " new types: " + Arrays.deepToString(types));
+                i--;
+            } else if (types[i] instanceof TypeVariable &&
+                    !(parameters[i] instanceof Variant))
+                // its an unwrapped variant, wrap it
+                parameters[i] = new Variant<Object>(parameters[i]);
+            else if (parameters[i] instanceof DBusInterface)
+                parameters[i] = conn.getExportedObject((DBusInterface) parameters[i]);
+        }
+        return parameters;
+    }
+
+    @SuppressWarnings("unchecked")
+    static Object deSerializeParameter(Object parameter, Type type, AbstractConnection conn) throws Exception {
+        if (Debug.debug)
+            Debug.print(Debug.VERBOSE, "Deserializing from " + parameter.getClass() + " to " + type.getClass());
+        if (null == parameter)
+            return null;
+
+        // its a wrapped variant, unwrap it
+        if (type instanceof TypeVariable
+                && parameter instanceof Variant) {
+            parameter = ((Variant) parameter).getValue();
+        }
+
+        // Turn a signature into a Type[]
+        if (type instanceof Class
+                && ((Class) type).isArray()
+                && ((Class) type).getComponentType().equals(Type.class)
+                && parameter instanceof String) {
+            Vector<Type> rv = new Vector<Type>();
+            getJavaType((String) parameter, rv, -1);
+            parameter = rv.toArray(new Type[0]);
+        }
+
+        // its an object path, get/create the proxy
+        if (parameter instanceof ObjectPath) {
+            if (type instanceof Class && DBusInterface.class.isAssignableFrom((Class) type))
+                parameter = conn.getExportedObject(
+                        ((ObjectPath) parameter).source,
+                        ((ObjectPath) parameter).path);
+            else
+                parameter = new Path(((ObjectPath) parameter).path);
+        }
+
+        // it should be a struct. create it
+        if (parameter instanceof Object[] &&
+                type instanceof Class &&
+                Struct.class.isAssignableFrom((Class) type)) {
+            if (Debug.debug) Debug.print(Debug.VERBOSE, "Creating Struct " + type + " from " + parameter);
+            Type[] ts = Container.getTypeCache(type);
+            if (null == ts) {
+                Field[] fs = ((Class) type).getDeclaredFields();
+                ts = new Type[fs.length];
+                for (Field f : fs) {
+                    Position p = f.getAnnotation(Position.class);
+                    if (null == p) continue;
+                    ts[p.value()] = f.getGenericType();
+                }
+                Container.putTypeCache(type, ts);
+            }
+
+            // recurse over struct contents
+            parameter = deSerializeParameters((Object[]) parameter, ts, conn);
+            for (Constructor con : ((Class) type).getDeclaredConstructors()) {
+                try {
+                    parameter = con.newInstance((Object[]) parameter);
+                    break;
+                } catch (IllegalArgumentException IAe) {
+                }
+            }
+        }
+
+        // recurse over arrays
+        if (parameter instanceof Object[]) {
+            Type[] ts = new Type[((Object[]) parameter).length];
+            Arrays.fill(ts, parameter.getClass().getComponentType());
+            parameter = deSerializeParameters((Object[]) parameter,
+                    ts, conn);
+        }
+        if (parameter instanceof List) {
+            Type type2;
+            if (type instanceof ParameterizedType)
+                type2 = ((ParameterizedType) type).getActualTypeArguments()[0];
+            else if (type instanceof GenericArrayType)
+                type2 = ((GenericArrayType) type).getGenericComponentType();
+            else if (type instanceof Class && ((Class) type).isArray())
+                type2 = ((Class) type).getComponentType();
+            else
+                type2 = null;
+            if (null != type2)
+                parameter = deSerializeParameters((List) parameter, type2, conn);
+        }
+
+        // correct floats if appropriate
+        if (type.equals(Float.class) || type.equals(Float.TYPE))
+            if (!(parameter instanceof Float))
+                parameter = ((Number) parameter).floatValue();
+
+        // make sure arrays are in the correct format
+        if (parameter instanceof Object[] ||
+                parameter instanceof List ||
+                parameter.getClass().isArray()) {
+            if (type instanceof ParameterizedType)
+                parameter = ArrayFrob.convert(parameter,
+                        (Class<? extends Object>) ((ParameterizedType) type).getRawType());
+            else if (type instanceof GenericArrayType) {
+                Type ct = ((GenericArrayType) type).getGenericComponentType();
+                Class cc = null;
+                if (ct instanceof Class)
+                    cc = (Class) ct;
+                if (ct instanceof ParameterizedType)
+                    cc = (Class) ((ParameterizedType) ct).getRawType();
+                Object o = Array.newInstance(cc, 0);
+                parameter = ArrayFrob.convert(parameter,
+                        o.getClass());
+            } else if (type instanceof Class &&
+                    ((Class) type).isArray()) {
+                Class cc = ((Class) type).getComponentType();
+                if ((cc.equals(Float.class) || cc.equals(Float.TYPE))
+                        && (parameter instanceof double[])) {
+                    double[] tmp1 = (double[]) parameter;
+                    float[] tmp2 = new float[tmp1.length];
+                    for (int i = 0; i < tmp1.length; i++)
+                        tmp2[i] = (float) tmp1[i];
+                    parameter = tmp2;
+                }
+                Object o = Array.newInstance(cc, 0);
+                parameter = ArrayFrob.convert(parameter,
+                        o.getClass());
+            }
+        }
+        if (parameter instanceof DBusMap) {
+            if (Debug.debug) Debug.print(Debug.VERBOSE, "Deserializing a Map");
+            DBusMap dmap = (DBusMap) parameter;
+            Type[] maptypes = ((ParameterizedType) type).getActualTypeArguments();
+            for (int i = 0; i < dmap.entries.length; i++) {
+                dmap.entries[i][0] = deSerializeParameter(dmap.entries[i][0], maptypes[0], conn);
+                dmap.entries[i][1] = deSerializeParameter(dmap.entries[i][1], maptypes[1], conn);
+            }
+        }
+        return parameter;
+    }
+
+    static List<Object> deSerializeParameters(List<Object> parameters, Type type, AbstractConnection conn) throws Exception {
+        if (Debug.debug) Debug.print(Debug.VERBOSE, "Deserializing from " + parameters + " to " + type);
+        if (null == parameters) return null;
+        for (int i = 0; i < parameters.size(); i++) {
+            if (null == parameters.get(i)) continue;
+
+         /* DO NOT DO THIS! IT'S REALLY NOT SUPPORTED! 
+          * if (type instanceof Class &&
+               DBusSerializable.class.isAssignableFrom((Class) types[i])) {
+            for (Method m: ((Class) types[i]).getDeclaredMethods()) 
+               if (m.getName().equals("deserialize")) {
+                  Type[] newtypes = m.getGenericParameterTypes();
+                  try {
+                     Object[] sub = new Object[newtypes.length];
+                     System.arraycopy(parameters, i, sub, 0, newtypes.length); 
+                     sub = deSerializeParameters(sub, newtypes, conn);
+                     DBusSerializable sz = (DBusSerializable) ((Class) types[i]).newInstance();
+                     m.invoke(sz, sub);
+                     Object[] compress = new Object[parameters.length - newtypes.length + 1];
+                     System.arraycopy(parameters, 0, compress, 0, i);
+                     compress[i] = sz;
+                     System.arraycopy(parameters, i + newtypes.length, compress, i+1, parameters.length - i - newtypes.length);
+                     parameters = compress;
+                  } catch (ArrayIndexOutOfBoundsException AIOOBe) {
+                     if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, AIOOBe);
+                     throw new DBusException("Not enough elements to create custom object from serialized data ("+(parameters.size()-i)+" < "+(newtypes.length)+")");
+                  }
+               }
+         } else*/
+            parameters.set(i, deSerializeParameter(parameters.get(i), type, conn));
+        }
+        return parameters;
+    }
+
+    @SuppressWarnings("unchecked")
+    static Object[] deSerializeParameters(Object[] parameters, Type[] types, AbstractConnection conn) throws Exception {
+        if (Debug.debug)
+            Debug.print(Debug.VERBOSE, "Deserializing from " + Arrays.deepToString(parameters) + " to " + Arrays.deepToString(types));
+        if (null == parameters) return null;
+
+        if (types.length == 1 && types[0] instanceof ParameterizedType
+                && Tuple.class.isAssignableFrom((Class) ((ParameterizedType) types[0]).getRawType())) {
+            types = ((ParameterizedType) types[0]).getActualTypeArguments();
+        }
+
+        for (int i = 0; i < parameters.length; i++) {
+            // CHECK IF ARRAYS HAVE THE SAME LENGTH <-- has to happen after expanding parameters
+            if (i >= types.length) {
+                if (Debug.debug) {
+                    for (int j = 0; j < parameters.length; j++) {
+                        Debug.print(Debug.ERR, String.format("Error, Parameters difference (%1d, '%2s')", j, parameters[j].toString()));
+                    }
+                }
+                throw new DBusException(getString("errorDeserializingMessage"));
+            }
+            if (null == parameters[i]) continue;
+
+            if ((types[i] instanceof Class &&
+                    DBusSerializable.class.isAssignableFrom((Class<? extends Object>) types[i])) ||
+                    (types[i] instanceof ParameterizedType &&
+                            DBusSerializable.class.isAssignableFrom((Class<? extends Object>) ((ParameterizedType) types[i]).getRawType()))) {
+                Class<? extends DBusSerializable> dsc;
+                if (types[i] instanceof Class)
+                    dsc = (Class<? extends DBusSerializable>) types[i];
+                else
+                    dsc = (Class<? extends DBusSerializable>) ((ParameterizedType) types[i]).getRawType();
+                for (Method m : dsc.getDeclaredMethods())
+                    if (m.getName().equals("deserialize")) {
+                        Type[] newtypes = m.getGenericParameterTypes();
+                        try {
+                            Object[] sub = new Object[newtypes.length];
+                            System.arraycopy(parameters, i, sub, 0, newtypes.length);
+                            sub = deSerializeParameters(sub, newtypes, conn);
+                            DBusSerializable sz = dsc.newInstance();
+                            m.invoke(sz, sub);
+                            Object[] compress = new Object[parameters.length - newtypes.length + 1];
+                            System.arraycopy(parameters, 0, compress, 0, i);
+                            compress[i] = sz;
+                            System.arraycopy(parameters, i + newtypes.length, compress, i + 1, parameters.length - i - newtypes.length);
+                            parameters = compress;
+                        } catch (ArrayIndexOutOfBoundsException AIOOBe) {
+                            if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, AIOOBe);
+                            throw new DBusException(MessageFormat.format(getString("notEnoughElementsToCreateCustomObject"),
+                                    new Object[]{parameters.length - i, newtypes.length}));
+                        }
+                    }
+            } else
+                parameters[i] = deSerializeParameter(parameters[i], types[i], conn);
+        }
+        return parameters;
+    }
+}
+
+
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/Message.java b/federation/sssd/src/main/java/org/freedesktop/dbus/Message.java
new file mode 100644
index 0000000..01f00e8
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/Message.java
@@ -0,0 +1,1216 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import cx.ath.matthew.debug.Debug;
+import cx.ath.matthew.utils.Hexdump;
+import org.freedesktop.dbus.exceptions.DBusException;
+import org.freedesktop.dbus.exceptions.MarshallingException;
+import org.freedesktop.dbus.exceptions.UnknownTypeCodeException;
+
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.Array;
+import java.lang.reflect.Type;
+import java.text.MessageFormat;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Vector;
+
+import static org.freedesktop.dbus.Gettext.getString;
+
+/**
+ * Superclass of all messages which are sent over the Bus.
+ * This class deals with all the marshalling to/from the wire format.
+ */
+public class Message {
+    /**
+     * Defines constants representing the endianness of the message.
+     */
+    public static interface Endian {
+        public static final byte BIG = 'B';
+        public static final byte LITTLE = 'l';
+    }
+
+    /**
+     * Defines constants representing the flags which can be set on a message.
+     */
+    public static interface Flags {
+        public static final byte NO_REPLY_EXPECTED = 0x01;
+        public static final byte NO_AUTO_START = 0x02;
+        public static final byte ASYNC = 0x40;
+    }
+
+    /**
+     * Defines constants for each message type.
+     */
+    public static interface MessageType {
+        public static final byte METHOD_CALL = 1;
+        public static final byte METHOD_RETURN = 2;
+        public static final byte ERROR = 3;
+        public static final byte SIGNAL = 4;
+    }
+
+    /**
+     * The current protocol major version.
+     */
+    public static final byte PROTOCOL = 1;
+
+    /**
+     * Defines constants for each valid header field type.
+     */
+    public static interface HeaderField {
+        public static final byte PATH = 1;
+        public static final byte INTERFACE = 2;
+        public static final byte MEMBER = 3;
+        public static final byte ERROR_NAME = 4;
+        public static final byte REPLY_SERIAL = 5;
+        public static final byte DESTINATION = 6;
+        public static final byte SENDER = 7;
+        public static final byte SIGNATURE = 8;
+    }
+
+    /**
+     * Defines constants for each argument type.
+     * There are two constants for each argument type,
+     * as a byte or as a String (the _STRING version)
+     */
+    public static interface ArgumentType {
+        public static final String BYTE_STRING = "y";
+        public static final String BOOLEAN_STRING = "b";
+        public static final String INT16_STRING = "n";
+        public static final String UINT16_STRING = "q";
+        public static final String INT32_STRING = "i";
+        public static final String UINT32_STRING = "u";
+        public static final String INT64_STRING = "x";
+        public static final String UINT64_STRING = "t";
+        public static final String DOUBLE_STRING = "d";
+        public static final String FLOAT_STRING = "f";
+        public static final String STRING_STRING = "s";
+        public static final String OBJECT_PATH_STRING = "o";
+        public static final String SIGNATURE_STRING = "g";
+        public static final String ARRAY_STRING = "a";
+        public static final String VARIANT_STRING = "v";
+        public static final String STRUCT_STRING = "r";
+        public static final String STRUCT1_STRING = "(";
+        public static final String STRUCT2_STRING = ")";
+        public static final String DICT_ENTRY_STRING = "e";
+        public static final String DICT_ENTRY1_STRING = "{";
+        public static final String DICT_ENTRY2_STRING = "}";
+
+        public static final byte BYTE = 'y';
+        public static final byte BOOLEAN = 'b';
+        public static final byte INT16 = 'n';
+        public static final byte UINT16 = 'q';
+        public static final byte INT32 = 'i';
+        public static final byte UINT32 = 'u';
+        public static final byte INT64 = 'x';
+        public static final byte UINT64 = 't';
+        public static final byte DOUBLE = 'd';
+        public static final byte FLOAT = 'f';
+        public static final byte STRING = 's';
+        public static final byte OBJECT_PATH = 'o';
+        public static final byte SIGNATURE = 'g';
+        public static final byte ARRAY = 'a';
+        public static final byte VARIANT = 'v';
+        public static final byte STRUCT = 'r';
+        public static final byte STRUCT1 = '(';
+        public static final byte STRUCT2 = ')';
+        public static final byte DICT_ENTRY = 'e';
+        public static final byte DICT_ENTRY1 = '{';
+        public static final byte DICT_ENTRY2 = '}';
+    }
+
+    /**
+     * Keep a static reference to each size of padding array to prevent allocation.
+     */
+    private static byte[][] padding;
+
+    static {
+        padding = new byte[][]{
+                null,
+                new byte[1],
+                new byte[2],
+                new byte[3],
+                new byte[4],
+                new byte[5],
+                new byte[6],
+                new byte[7]};
+    }
+
+    /**
+     * Steps to increment the buffer array.
+     */
+    private static final int BUFFERINCREMENT = 20;
+
+    private boolean big;
+    protected byte[][] wiredata;
+    protected long bytecounter;
+    protected Map<Byte, Object> headers;
+    protected static long globalserial = 0;
+    protected long serial;
+    protected byte type;
+    protected byte flags;
+    protected byte protover;
+    private Object[] args;
+    private byte[] body;
+    private long bodylen = 0;
+    private int preallocated = 0;
+    private int paofs = 0;
+    private byte[] pabuf;
+    private int bufferuse = 0;
+
+    /**
+     * Returns the name of the given header field.
+     */
+    public static String getHeaderFieldName(byte field) {
+        switch (field) {
+            case HeaderField.PATH:
+                return "Path";
+            case HeaderField.INTERFACE:
+                return "Interface";
+            case HeaderField.MEMBER:
+                return "Member";
+            case HeaderField.ERROR_NAME:
+                return "Error Name";
+            case HeaderField.REPLY_SERIAL:
+                return "Reply Serial";
+            case HeaderField.DESTINATION:
+                return "Destination";
+            case HeaderField.SENDER:
+                return "Sender";
+            case HeaderField.SIGNATURE:
+                return "Signature";
+            default:
+                return "Invalid";
+        }
+    }
+
+    /**
+     * Create a message; only to be called by sub-classes.
+     *
+     * @param endian The endianness to create the message.
+     * @param type   The message type.
+     * @param flags  Any message flags.
+     */
+    protected Message(byte endian, byte type, byte flags) throws DBusException {
+        wiredata = new byte[BUFFERINCREMENT][];
+        headers = new HashMap<Byte, Object>();
+        big = (Endian.BIG == endian);
+        bytecounter = 0;
+        synchronized (Message.class) {
+            serial = ++globalserial;
+        }
+        if (Debug.debug) Debug.print(Debug.DEBUG, "Creating message with serial " + serial);
+        this.type = type;
+        this.flags = flags;
+        preallocate(4);
+        append("yyyy", endian, type, flags, Message.PROTOCOL);
+    }
+
+    /**
+     * Create a blank message. Only to be used when calling populate.
+     */
+    protected Message() {
+        wiredata = new byte[BUFFERINCREMENT][];
+        headers = new HashMap<Byte, Object>();
+        bytecounter = 0;
+    }
+
+    /**
+     * Create a message from wire-format data.
+     *
+     * @param msg     D-Bus serialized data of type yyyuu
+     * @param headers D-Bus serialized data of type a(yv)
+     * @param body    D-Bus serialized data of the signature defined in headers.
+     */
+    @SuppressWarnings("unchecked")
+    void populate(byte[] msg, byte[] headers, byte[] body) throws DBusException {
+        big = (msg[0] == Endian.BIG);
+        type = msg[1];
+        flags = msg[2];
+        protover = msg[3];
+        wiredata[0] = msg;
+        wiredata[1] = headers;
+        wiredata[2] = body;
+        this.body = body;
+        bufferuse = 3;
+        bodylen = ((Number) extract(Message.ArgumentType.UINT32_STRING, msg, 4)[0]).longValue();
+        serial = ((Number) extract(Message.ArgumentType.UINT32_STRING, msg, 8)[0]).longValue();
+        bytecounter = msg.length + headers.length + body.length;
+        if (Debug.debug) Debug.print(Debug.VERBOSE, headers);
+        Object[] hs = extract("a(yv)", headers, 0);
+        if (Debug.debug) Debug.print(Debug.VERBOSE, Arrays.deepToString(hs));
+        for (Object o : (Vector<Object>) hs[0]) {
+            this.headers.put((Byte) ((Object[]) o)[0], ((Variant<Object>) ((Object[]) o)[1]).getValue());
+        }
+    }
+
+    /**
+     * Create a buffer of num bytes.
+     * Data is copied to this rather than added to the buffer list.
+     */
+    private void preallocate(int num) {
+        preallocated = 0;
+        pabuf = new byte[num];
+        appendBytes(pabuf);
+        preallocated = num;
+        paofs = 0;
+    }
+
+    /**
+     * Ensures there are enough free buffers.
+     *
+     * @param num number of free buffers to create.
+     */
+    private void ensureBuffers(int num) {
+        int increase = num - wiredata.length + bufferuse;
+        if (increase > 0) {
+            if (increase < BUFFERINCREMENT) increase = BUFFERINCREMENT;
+            if (Debug.debug) Debug.print(Debug.VERBOSE, "Resizing " + bufferuse);
+            byte[][] temp = new byte[wiredata.length + increase][];
+            System.arraycopy(wiredata, 0, temp, 0, wiredata.length);
+            wiredata = temp;
+        }
+    }
+
+    /**
+     * Appends a buffer to the buffer list.
+     */
+    protected void appendBytes(byte[] buf) {
+        if (null == buf) return;
+        if (preallocated > 0) {
+            if (paofs + buf.length > pabuf.length)
+                throw new ArrayIndexOutOfBoundsException(MessageFormat.format(getString("arrayOutOfBounds"), new Object[]{paofs, pabuf.length, buf.length}));
+            System.arraycopy(buf, 0, pabuf, paofs, buf.length);
+            paofs += buf.length;
+            preallocated -= buf.length;
+        } else {
+            if (bufferuse == wiredata.length) {
+                if (Debug.debug) Debug.print(Debug.VERBOSE, "Resizing " + bufferuse);
+                byte[][] temp = new byte[wiredata.length + BUFFERINCREMENT][];
+                System.arraycopy(wiredata, 0, temp, 0, wiredata.length);
+                wiredata = temp;
+            }
+            wiredata[bufferuse++] = buf;
+            bytecounter += buf.length;
+        }
+    }
+
+    /**
+     * Appends a byte to the buffer list.
+     */
+    protected void appendByte(byte b) {
+        if (preallocated > 0) {
+            pabuf[paofs++] = b;
+            preallocated--;
+        } else {
+            if (bufferuse == wiredata.length) {
+                if (Debug.debug) Debug.print(Debug.VERBOSE, "Resizing " + bufferuse);
+                byte[][] temp = new byte[wiredata.length + BUFFERINCREMENT][];
+                System.arraycopy(wiredata, 0, temp, 0, wiredata.length);
+                wiredata = temp;
+            }
+            wiredata[bufferuse++] = new byte[]{b};
+            bytecounter++;
+        }
+    }
+
+    /**
+     * Demarshalls an integer of a given width from a buffer.
+     * Endianness is determined from the format of the message.
+     *
+     * @param buf   The buffer to demarshall from.
+     * @param ofs   The offset to demarshall from.
+     * @param width The byte-width of the int.
+     */
+    public long demarshallint(byte[] buf, int ofs, int width) {
+        return big ? demarshallintBig(buf, ofs, width) : demarshallintLittle(buf, ofs, width);
+    }
+
+    /**
+     * Demarshalls an integer of a given width from a buffer.
+     *
+     * @param buf    The buffer to demarshall from.
+     * @param ofs    The offset to demarshall from.
+     * @param endian The endianness to use in demarshalling.
+     * @param width  The byte-width of the int.
+     */
+    public static long demarshallint(byte[] buf, int ofs, byte endian, int width) {
+        return endian == Endian.BIG ? demarshallintBig(buf, ofs, width) : demarshallintLittle(buf, ofs, width);
+    }
+
+    /**
+     * Demarshalls an integer of a given width from a buffer using big-endian format.
+     *
+     * @param buf   The buffer to demarshall from.
+     * @param ofs   The offset to demarshall from.
+     * @param width The byte-width of the int.
+     */
+    public static long demarshallintBig(byte[] buf, int ofs, int width) {
+        long l = 0;
+        for (int i = 0; i < width; i++) {
+            l <<= 8;
+            l |= (buf[ofs + i] & 0xFF);
+        }
+        return l;
+    }
+
+    /**
+     * Demarshalls an integer of a given width from a buffer using little-endian format.
+     *
+     * @param buf   The buffer to demarshall from.
+     * @param ofs   The offset to demarshall from.
+     * @param width The byte-width of the int.
+     */
+    public static long demarshallintLittle(byte[] buf, int ofs, int width) {
+        long l = 0;
+        for (int i = (width - 1); i >= 0; i--) {
+            l <<= 8;
+            l |= (buf[ofs + i] & 0xFF);
+        }
+        return l;
+    }
+
+    /**
+     * Marshalls an integer of a given width and appends it to the message.
+     * Endianness is determined from the message.
+     *
+     * @param l     The integer to marshall.
+     * @param width The byte-width of the int.
+     */
+    public void appendint(long l, int width) {
+        byte[] buf = new byte[width];
+        marshallint(l, buf, 0, width);
+        appendBytes(buf);
+    }
+
+    /**
+     * Marshalls an integer of a given width into a buffer.
+     * Endianness is determined from the message.
+     *
+     * @param l     The integer to marshall.
+     * @param buf   The buffer to marshall to.
+     * @param ofs   The offset to marshall to.
+     * @param width The byte-width of the int.
+     */
+    public void marshallint(long l, byte[] buf, int ofs, int width) {
+        if (big) marshallintBig(l, buf, ofs, width);
+        else marshallintLittle(l, buf, ofs, width);
+        if (Debug.debug) Debug.print(Debug.VERBOSE, "Marshalled int " + l + " to " + Hexdump.toHex(buf, ofs, width));
+    }
+
+    /**
+     * Marshalls an integer of a given width into a buffer using big-endian format.
+     *
+     * @param l     The integer to marshall.
+     * @param buf   The buffer to marshall to.
+     * @param ofs   The offset to marshall to.
+     * @param width The byte-width of the int.
+     */
+    public static void marshallintBig(long l, byte[] buf, int ofs, int width) {
+        for (int i = (width - 1); i >= 0; i--) {
+            buf[i + ofs] = (byte) (l & 0xFF);
+            l >>= 8;
+        }
+    }
+
+    /**
+     * Marshalls an integer of a given width into a buffer using little-endian format.
+     *
+     * @param l     The integer to marshall.
+     * @param buf   The buffer to demarshall to.
+     * @param ofs   The offset to demarshall to.
+     * @param width The byte-width of the int.
+     */
+    public static void marshallintLittle(long l, byte[] buf, int ofs, int width) {
+        for (int i = 0; i < width; i++) {
+            buf[i + ofs] = (byte) (l & 0xFF);
+            l >>= 8;
+        }
+    }
+
+    public byte[][] getWireData() {
+        return wiredata;
+    }
+
+    /**
+     * Formats the message in a human-readable format.
+     */
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+        sb.append(getClass().getSimpleName());
+        sb.append('(');
+        sb.append(flags);
+        sb.append(',');
+        sb.append(serial);
+        sb.append(')');
+        sb.append(' ');
+        sb.append('{');
+        sb.append(' ');
+        if (headers.size() == 0)
+            sb.append('}');
+        else {
+            for (Byte field : headers.keySet()) {
+                sb.append(getHeaderFieldName(field));
+                sb.append('=');
+                sb.append('>');
+                sb.append(headers.get(field).toString());
+                sb.append(',');
+                sb.append(' ');
+            }
+            sb.setCharAt(sb.length() - 2, ' ');
+            sb.setCharAt(sb.length() - 1, '}');
+        }
+        sb.append(' ');
+        sb.append('{');
+        sb.append(' ');
+        Object[] args = null;
+        try {
+            args = getParameters();
+        } catch (DBusException DBe) {
+            if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBe);
+        }
+        if (null == args || 0 == args.length)
+            sb.append('}');
+        else {
+            for (Object o : args) {
+                if (o instanceof Object[])
+                    sb.append(Arrays.deepToString((Object[]) o));
+                else if (o instanceof byte[])
+                    sb.append(Arrays.toString((byte[]) o));
+                else if (o instanceof int[])
+                    sb.append(Arrays.toString((int[]) o));
+                else if (o instanceof short[])
+                    sb.append(Arrays.toString((short[]) o));
+                else if (o instanceof long[])
+                    sb.append(Arrays.toString((long[]) o));
+                else if (o instanceof boolean[])
+                    sb.append(Arrays.toString((boolean[]) o));
+                else if (o instanceof double[])
+                    sb.append(Arrays.toString((double[]) o));
+                else if (o instanceof float[])
+                    sb.append(Arrays.toString((float[]) o));
+                else
+                    sb.append(o.toString());
+                sb.append(',');
+                sb.append(' ');
+            }
+            sb.setCharAt(sb.length() - 2, ' ');
+            sb.setCharAt(sb.length() - 1, '}');
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Returns the value of the header field of a given field.
+     *
+     * @param type The field to return.
+     * @return The value of the field or null if unset.
+     */
+    public Object getHeader(byte type) {
+        return headers.get(type);
+    }
+
+    /**
+     * Appends a value to the message.
+     * The type of the value is read from a D-Bus signature and used to marshall
+     * the value.
+     *
+     * @param sigb   A buffer of the D-Bus signature.
+     * @param sigofs The offset into the signature corresponding to this value.
+     * @param data   The value to marshall.
+     * @return The offset into the signature of the end of this value's type.
+     */
+    @SuppressWarnings("unchecked")
+    private int appendone(byte[] sigb, int sigofs, Object data) throws DBusException {
+        try {
+            int i = sigofs;
+            if (Debug.debug) Debug.print(Debug.VERBOSE, (Object) bytecounter);
+            if (Debug.debug) Debug.print(Debug.VERBOSE, "Appending type: " + ((char) sigb[i]) + " value: " + data);
+
+            // pad to the alignment of this type.
+            pad(sigb[i]);
+            switch (sigb[i]) {
+                case ArgumentType.BYTE:
+                    appendByte(((Number) data).byteValue());
+                    break;
+                case ArgumentType.BOOLEAN:
+                    appendint(((Boolean) data).booleanValue() ? 1 : 0, 4);
+                    break;
+                case ArgumentType.DOUBLE:
+                    long l = Double.doubleToLongBits(((Number) data).doubleValue());
+                    appendint(l, 8);
+                    break;
+                case ArgumentType.FLOAT:
+                    int rf = Float.floatToIntBits(((Number) data).floatValue());
+                    appendint(rf, 4);
+                    break;
+                case ArgumentType.UINT32:
+                    appendint(((Number) data).longValue(), 4);
+                    break;
+                case ArgumentType.INT64:
+                    appendint(((Number) data).longValue(), 8);
+                    break;
+                case ArgumentType.UINT64:
+                    if (big) {
+                        appendint(((UInt64) data).top(), 4);
+                        appendint(((UInt64) data).bottom(), 4);
+                    } else {
+                        appendint(((UInt64) data).bottom(), 4);
+                        appendint(((UInt64) data).top(), 4);
+                    }
+                    break;
+                case ArgumentType.INT32:
+                    appendint(((Number) data).intValue(), 4);
+                    break;
+                case ArgumentType.UINT16:
+                    appendint(((Number) data).intValue(), 2);
+                    break;
+                case ArgumentType.INT16:
+                    appendint(((Number) data).shortValue(), 2);
+                    break;
+                case ArgumentType.STRING:
+                case ArgumentType.OBJECT_PATH:
+                    // Strings are marshalled as a UInt32 with the length,
+                    // followed by the String, followed by a null byte.
+                    String payload = data.toString();
+                    byte[] payloadbytes = null;
+                    try {
+                        payloadbytes = payload.getBytes("UTF-8");
+                    } catch (UnsupportedEncodingException UEe) {
+                        if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(UEe);
+                        throw new DBusException(getString("utf8NotSupported"));
+                    }
+                    if (Debug.debug) Debug.print(Debug.VERBOSE, "Appending String of length " + payloadbytes.length);
+                    appendint(payloadbytes.length, 4);
+                    appendBytes(payloadbytes);
+                    appendBytes(padding[1]);
+                    //pad(ArgumentType.STRING);? do we need this?
+                    break;
+                case ArgumentType.SIGNATURE:
+                    // Signatures are marshalled as a byte with the length,
+                    // followed by the String, followed by a null byte.
+                    // Signatures are generally short, so preallocate the array
+                    // for the string, length and null byte.
+                    if (data instanceof Type[])
+                        payload = Marshalling.getDBusType((Type[]) data);
+                    else
+                        payload = (String) data;
+                    byte[] pbytes = payload.getBytes();
+                    preallocate(2 + pbytes.length);
+                    appendByte((byte) pbytes.length);
+                    appendBytes(pbytes);
+                    appendByte((byte) 0);
+                    break;
+                case ArgumentType.ARRAY:
+                    // Arrays are given as a UInt32 for the length in bytes,
+                    // padding to the element alignment, then elements in
+                    // order. The length is the length from the end of the
+                    // initial padding to the end of the last element.
+                    if (Debug.debug) {
+                        if (data instanceof Object[])
+                            Debug.print(Debug.VERBOSE, "Appending array: " + Arrays.deepToString((Object[]) data));
+                    }
+
+                    byte[] alen = new byte[4];
+                    appendBytes(alen);
+                    pad(sigb[++i]);
+                    long c = bytecounter;
+
+                    // optimise primatives
+                    if (data.getClass().isArray() &&
+                            data.getClass().getComponentType().isPrimitive()) {
+                        byte[] primbuf;
+                        int algn = getAlignment(sigb[i]);
+                        int len = Array.getLength(data);
+                        switch (sigb[i]) {
+                            case ArgumentType.BYTE:
+                                primbuf = (byte[]) data;
+                                break;
+                            case ArgumentType.INT16:
+                            case ArgumentType.INT32:
+                            case ArgumentType.INT64:
+                                primbuf = new byte[len * algn];
+                                for (int j = 0, k = 0; j < len; j++, k += algn)
+                                    marshallint(Array.getLong(data, j), primbuf, k, algn);
+                                break;
+                            case ArgumentType.BOOLEAN:
+                                primbuf = new byte[len * algn];
+                                for (int j = 0, k = 0; j < len; j++, k += algn)
+                                    marshallint(Array.getBoolean(data, j) ? 1 : 0, primbuf, k, algn);
+                                break;
+                            case ArgumentType.DOUBLE:
+                                primbuf = new byte[len * algn];
+                                if (data instanceof float[])
+                                    for (int j = 0, k = 0; j < len; j++, k += algn)
+                                        marshallint(Double.doubleToRawLongBits(((float[]) data)[j]),
+                                                primbuf, k, algn);
+                                else
+                                    for (int j = 0, k = 0; j < len; j++, k += algn)
+                                        marshallint(Double.doubleToRawLongBits(((double[]) data)[j]),
+                                                primbuf, k, algn);
+                                break;
+                            case ArgumentType.FLOAT:
+                                primbuf = new byte[len * algn];
+                                for (int j = 0, k = 0; j < len; j++, k += algn)
+                                    marshallint(
+                                            Float.floatToRawIntBits(((float[]) data)[j]),
+                                            primbuf, k, algn);
+                                break;
+                            default:
+                                throw new MarshallingException(getString("arraySentAsNonPrimitive"));
+                        }
+                        appendBytes(primbuf);
+                    } else if (data instanceof List) {
+                        Object[] contents = ((List) data).toArray();
+                        int diff = i;
+                        ensureBuffers(contents.length * 4);
+                        for (Object o : contents)
+                            diff = appendone(sigb, i, o);
+                        i = diff;
+                    } else if (data instanceof Map) {
+                        int diff = i;
+                        ensureBuffers(((Map) data).size() * 6);
+                        for (Map.Entry<Object, Object> o : ((Map<Object, Object>) data).entrySet())
+                            diff = appendone(sigb, i, o);
+                        if (i == diff) {
+                            // advance the type parser even on 0-size arrays.
+                            Vector<Type> temp = new Vector<Type>();
+                            byte[] temp2 = new byte[sigb.length - diff];
+                            System.arraycopy(sigb, diff, temp2, 0, temp2.length);
+                            String temp3 = new String(temp2);
+                            int temp4 = Marshalling.getJavaType(temp3, temp, 1);
+                            diff += temp4;
+                        }
+                        i = diff;
+                    } else {
+                        Object[] contents = (Object[]) data;
+                        ensureBuffers(contents.length * 4);
+                        int diff = i;
+                        for (Object o : contents)
+                            diff = appendone(sigb, i, o);
+                        i = diff;
+                    }
+                    if (Debug.debug)
+                        Debug.print(Debug.VERBOSE, "start: " + c + " end: " + bytecounter + " length: " + (bytecounter - c));
+                    marshallint(bytecounter - c, alen, 0, 4);
+                    break;
+                case ArgumentType.STRUCT1:
+                    // Structs are aligned to 8 bytes
+                    // and simply contain each element marshalled in order
+                    Object[] contents;
+                    if (data instanceof Container)
+                        contents = ((Container) data).getParameters();
+                    else
+                        contents = (Object[]) data;
+                    ensureBuffers(contents.length * 4);
+                    int j = 0;
+                    for (i++; sigb[i] != ArgumentType.STRUCT2; i++)
+                        i = appendone(sigb, i, contents[j++]);
+                    break;
+                case ArgumentType.DICT_ENTRY1:
+                    // Dict entries are the same as structs.
+                    if (data instanceof Map.Entry) {
+                        i++;
+                        i = appendone(sigb, i, ((Map.Entry) data).getKey());
+                        i++;
+                        i = appendone(sigb, i, ((Map.Entry) data).getValue());
+                        i++;
+                    } else {
+                        contents = (Object[]) data;
+                        j = 0;
+                        for (i++; sigb[i] != ArgumentType.DICT_ENTRY2; i++)
+                            i = appendone(sigb, i, contents[j++]);
+                    }
+                    break;
+                case ArgumentType.VARIANT:
+                    // Variants are marshalled as a signature
+                    // followed by the value.
+                    if (data instanceof Variant) {
+                        Variant var = (Variant) data;
+                        appendone(new byte[]{ArgumentType.SIGNATURE}, 0, var.getSig());
+                        appendone((var.getSig()).getBytes(), 0, var.getValue());
+                    } else if (data instanceof Object[]) {
+                        contents = (Object[]) data;
+                        appendone(new byte[]{ArgumentType.SIGNATURE}, 0, contents[0]);
+                        appendone(((String) contents[0]).getBytes(), 0, contents[1]);
+                    } else {
+                        String sig = Marshalling.getDBusType(data.getClass())[0];
+                        appendone(new byte[]{ArgumentType.SIGNATURE}, 0, sig);
+                        appendone((sig).getBytes(), 0, data);
+                    }
+                    break;
+            }
+            return i;
+        } catch (ClassCastException CCe) {
+            if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, CCe);
+            throw new MarshallingException(MessageFormat.format(getString("unconvertableType"), new Object[]{data.getClass().getName(), sigb[sigofs]}));
+        }
+    }
+
+    /**
+     * Pad the message to the proper alignment for the given type.
+     */
+    public void pad(byte type) {
+        if (Debug.debug) Debug.print(Debug.VERBOSE, "padding for " + (char) type);
+        int a = getAlignment(type);
+        if (Debug.debug) Debug.print(Debug.VERBOSE, preallocated + " " + paofs + " " + bytecounter + " " + a);
+        int b = (int) ((bytecounter - preallocated) % a);
+        if (0 == b) return;
+        a = (a - b);
+        if (preallocated > 0) {
+            paofs += a;
+            preallocated -= a;
+        } else
+            appendBytes(padding[a]);
+        if (Debug.debug) Debug.print(Debug.VERBOSE, preallocated + " " + paofs + " " + bytecounter + " " + a);
+    }
+
+    /**
+     * Return the alignment for a given type.
+     */
+    public static int getAlignment(byte type) {
+        switch (type) {
+            case 2:
+            case ArgumentType.INT16:
+            case ArgumentType.UINT16:
+                return 2;
+            case 4:
+            case ArgumentType.BOOLEAN:
+            case ArgumentType.FLOAT:
+            case ArgumentType.INT32:
+            case ArgumentType.UINT32:
+            case ArgumentType.STRING:
+            case ArgumentType.OBJECT_PATH:
+            case ArgumentType.ARRAY:
+                return 4;
+            case 8:
+            case ArgumentType.INT64:
+            case ArgumentType.UINT64:
+            case ArgumentType.DOUBLE:
+            case ArgumentType.STRUCT:
+            case ArgumentType.DICT_ENTRY:
+            case ArgumentType.STRUCT1:
+            case ArgumentType.DICT_ENTRY1:
+            case ArgumentType.STRUCT2:
+            case ArgumentType.DICT_ENTRY2:
+                return 8;
+            case 1:
+            case ArgumentType.BYTE:
+            case ArgumentType.SIGNATURE:
+            case ArgumentType.VARIANT:
+            default:
+                return 1;
+        }
+    }
+
+    /**
+     * Append a series of values to the message.
+     *
+     * @param sig  The signature(s) of the value(s).
+     * @param data The value(s).
+     */
+    public void append(String sig, Object... data) throws DBusException {
+        if (Debug.debug) Debug.print(Debug.DEBUG, "Appending sig: " + sig + " data: " + Arrays.deepToString(data));
+        byte[] sigb = sig.getBytes();
+        int j = 0;
+        for (int i = 0; i < sigb.length; i++) {
+            if (Debug.debug) Debug.print(Debug.VERBOSE, "Appending item: " + i + " " + ((char) sigb[i]) + " " + j);
+            i = appendone(sigb, i, data[j++]);
+        }
+    }
+
+    /**
+     * Align a counter to the given type.
+     *
+     * @param current The current counter.
+     * @param type    The type to align to.
+     * @return The new, aligned, counter.
+     */
+    public int align(int current, byte type) {
+        if (Debug.debug) Debug.print(Debug.VERBOSE, "aligning to " + (char) type);
+        int a = getAlignment(type);
+        if (0 == (current % a)) return current;
+        return current + (a - (current % a));
+    }
+
+    /**
+     * Demarshall one value from a buffer.
+     *
+     * @param sigb      A buffer of the D-Bus signature.
+     * @param buf       The buffer to demarshall from.
+     * @param ofs       An array of two ints, the offset into the signature buffer
+     *                  and the offset into the data buffer. These values will be
+     *                  updated to the start of the next value ofter demarshalling.
+     * @param contained converts nested arrays to Lists
+     * @return The demarshalled value.
+     */
+    private Object extractone(byte[] sigb, byte[] buf, int[] ofs, boolean contained) throws DBusException {
+        if (Debug.debug)
+            Debug.print(Debug.VERBOSE, "Extracting type: " + ((char) sigb[ofs[0]]) + " from offset " + ofs[1]);
+        Object rv = null;
+        ofs[1] = align(ofs[1], sigb[ofs[0]]);
+        switch (sigb[ofs[0]]) {
+            case ArgumentType.BYTE:
+                rv = buf[ofs[1]++];
+                break;
+            case ArgumentType.UINT32:
+                rv = new UInt32(demarshallint(buf, ofs[1], 4));
+                ofs[1] += 4;
+                break;
+            case ArgumentType.INT32:
+                rv = (int) demarshallint(buf, ofs[1], 4);
+                ofs[1] += 4;
+                break;
+            case ArgumentType.INT16:
+                rv = (short) demarshallint(buf, ofs[1], 2);
+                ofs[1] += 2;
+                break;
+            case ArgumentType.UINT16:
+                rv = new UInt16((int) demarshallint(buf, ofs[1], 2));
+                ofs[1] += 2;
+                break;
+            case ArgumentType.INT64:
+                rv = demarshallint(buf, ofs[1], 8);
+                ofs[1] += 8;
+                break;
+            case ArgumentType.UINT64:
+                long top;
+                long bottom;
+                if (big) {
+                    top = demarshallint(buf, ofs[1], 4);
+                    ofs[1] += 4;
+                    bottom = demarshallint(buf, ofs[1], 4);
+                } else {
+                    bottom = demarshallint(buf, ofs[1], 4);
+                    ofs[1] += 4;
+                    top = demarshallint(buf, ofs[1], 4);
+                }
+                rv = new UInt64(top, bottom);
+                ofs[1] += 4;
+                break;
+            case ArgumentType.DOUBLE:
+                long l = demarshallint(buf, ofs[1], 8);
+                ofs[1] += 8;
+                rv = Double.longBitsToDouble(l);
+                break;
+            case ArgumentType.FLOAT:
+                int rf = (int) demarshallint(buf, ofs[1], 4);
+                ofs[1] += 4;
+                rv = Float.intBitsToFloat(rf);
+                break;
+            case ArgumentType.BOOLEAN:
+                rf = (int) demarshallint(buf, ofs[1], 4);
+                ofs[1] += 4;
+                rv = (1 == rf) ? Boolean.TRUE : Boolean.FALSE;
+                break;
+            case ArgumentType.ARRAY:
+                long size = demarshallint(buf, ofs[1], 4);
+                if (Debug.debug) Debug.print(Debug.VERBOSE, "Reading array of size: " + size);
+                ofs[1] += 4;
+                byte algn = (byte) getAlignment(sigb[++ofs[0]]);
+                ofs[1] = align(ofs[1], sigb[ofs[0]]);
+                int length = (int) (size / algn);
+                if (length > DBusConnection.MAX_ARRAY_LENGTH)
+                    throw new MarshallingException(getString("arrayMustNotExceed") + DBusConnection.MAX_ARRAY_LENGTH);
+                // optimise primatives
+                switch (sigb[ofs[0]]) {
+                    case ArgumentType.BYTE:
+                        rv = new byte[length];
+                        System.arraycopy(buf, ofs[1], rv, 0, length);
+                        ofs[1] += size;
+                        break;
+                    case ArgumentType.INT16:
+                        rv = new short[length];
+                        for (int j = 0; j < length; j++, ofs[1] += algn)
+                            ((short[]) rv)[j] = (short) demarshallint(buf, ofs[1], algn);
+                        break;
+                    case ArgumentType.INT32:
+                        rv = new int[length];
+                        for (int j = 0; j < length; j++, ofs[1] += algn)
+                            ((int[]) rv)[j] = (int) demarshallint(buf, ofs[1], algn);
+                        break;
+                    case ArgumentType.INT64:
+                        rv = new long[length];
+                        for (int j = 0; j < length; j++, ofs[1] += algn)
+                            ((long[]) rv)[j] = demarshallint(buf, ofs[1], algn);
+                        break;
+                    case ArgumentType.BOOLEAN:
+                        rv = new boolean[length];
+                        for (int j = 0; j < length; j++, ofs[1] += algn)
+                            ((boolean[]) rv)[j] = (1 == demarshallint(buf, ofs[1], algn));
+                        break;
+                    case ArgumentType.FLOAT:
+                        rv = new float[length];
+                        for (int j = 0; j < length; j++, ofs[1] += algn)
+                            ((float[]) rv)[j] =
+                                    Float.intBitsToFloat((int) demarshallint(buf, ofs[1], algn));
+                        break;
+                    case ArgumentType.DOUBLE:
+                        rv = new double[length];
+                        for (int j = 0; j < length; j++, ofs[1] += algn)
+                            ((double[]) rv)[j] =
+                                    Double.longBitsToDouble(demarshallint(buf, ofs[1], algn));
+                        break;
+                    case ArgumentType.DICT_ENTRY1:
+                        if (0 == size) {
+                            // advance the type parser even on 0-size arrays.
+                            Vector<Type> temp = new Vector<Type>();
+                            byte[] temp2 = new byte[sigb.length - ofs[0]];
+                            System.arraycopy(sigb, ofs[0], temp2, 0, temp2.length);
+                            String temp3 = new String(temp2);
+                            // ofs[0] gets incremented anyway. Leave one character on the stack
+                            int temp4 = Marshalling.getJavaType(temp3, temp, 1) - 1;
+                            ofs[0] += temp4;
+                            if (Debug.debug)
+                                Debug.print(Debug.VERBOSE, "Aligned type: " + temp3 + " " + temp4 + " " + ofs[0]);
+                        }
+                        int ofssave = ofs[0];
+                        long end = ofs[1] + size;
+                        Vector<Object[]> entries = new Vector<Object[]>();
+                        while (ofs[1] < end) {
+                            ofs[0] = ofssave;
+                            entries.add((Object[]) extractone(sigb, buf, ofs, true));
+                        }
+                        rv = new DBusMap<Object, Object>(entries.toArray(new Object[0][]));
+                        break;
+                    default:
+                        if (0 == size) {
+                            // advance the type parser even on 0-size arrays.
+                            Vector<Type> temp = new Vector<Type>();
+                            byte[] temp2 = new byte[sigb.length - ofs[0]];
+                            System.arraycopy(sigb, ofs[0], temp2, 0, temp2.length);
+                            String temp3 = new String(temp2);
+                            // ofs[0] gets incremented anyway. Leave one character on the stack
+                            int temp4 = Marshalling.getJavaType(temp3, temp, 1) - 1;
+                            ofs[0] += temp4;
+                            if (Debug.debug)
+                                Debug.print(Debug.VERBOSE, "Aligned type: " + temp3 + " " + temp4 + " " + ofs[0]);
+                        }
+                        ofssave = ofs[0];
+                        end = ofs[1] + size;
+                        Vector<Object> contents = new Vector<Object>();
+                        while (ofs[1] < end) {
+                            ofs[0] = ofssave;
+                            contents.add(extractone(sigb, buf, ofs, true));
+                        }
+                        rv = contents;
+                }
+                if (contained && !(rv instanceof List) && !(rv instanceof Map))
+                    rv = ArrayFrob.listify(rv);
+                break;
+            case ArgumentType.STRUCT1:
+                Vector<Object> contents = new Vector<Object>();
+                while (sigb[++ofs[0]] != ArgumentType.STRUCT2)
+                    contents.add(extractone(sigb, buf, ofs, true));
+                rv = contents.toArray();
+                break;
+            case ArgumentType.DICT_ENTRY1:
+                Object[] decontents = new Object[2];
+                if (Debug.debug)
+                    Debug.print(Debug.VERBOSE, "Extracting Dict Entry (" + Hexdump.toAscii(sigb, ofs[0], sigb.length - ofs[0]) + ") from: " + Hexdump.toHex(buf, ofs[1], buf.length - ofs[1]));
+                ofs[0]++;
+                decontents[0] = extractone(sigb, buf, ofs, true);
+                ofs[0]++;
+                decontents[1] = extractone(sigb, buf, ofs, true);
+                ofs[0]++;
+                rv = decontents;
+                break;
+            case ArgumentType.VARIANT:
+                int[] newofs = new int[]{0, ofs[1]};
+                String sig = (String) extract(ArgumentType.SIGNATURE_STRING, buf, newofs)[0];
+                newofs[0] = 0;
+                rv = new Variant<Object>(extract(sig, buf, newofs)[0], sig);
+                ofs[1] = newofs[1];
+                break;
+            case ArgumentType.STRING:
+                length = (int) demarshallint(buf, ofs[1], 4);
+                ofs[1] += 4;
+                try {
+                    rv = new String(buf, ofs[1], length, "UTF-8");
+                } catch (UnsupportedEncodingException UEe) {
+                    if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(UEe);
+                    throw new DBusException(getString("utf8NotSupported"));
+                }
+                ofs[1] += length + 1;
+                break;
+            case ArgumentType.OBJECT_PATH:
+                length = (int) demarshallint(buf, ofs[1], 4);
+                ofs[1] += 4;
+                rv = new ObjectPath(getSource(), new String(buf, ofs[1], length));
+                ofs[1] += length + 1;
+                break;
+            case ArgumentType.SIGNATURE:
+                length = (buf[ofs[1]++] & 0xFF);
+                rv = new String(buf, ofs[1], length);
+                ofs[1] += length + 1;
+                break;
+            default:
+                throw new UnknownTypeCodeException(sigb[ofs[0]]);
+        }
+        if (Debug.debug) if (rv instanceof Object[])
+            Debug.print(Debug.VERBOSE, "Extracted: " + Arrays.deepToString((Object[]) rv) + " (now at " + ofs[1] + ")");
+        else
+            Debug.print(Debug.VERBOSE, "Extracted: " + rv + " (now at " + ofs[1] + ")");
+        return rv;
+    }
+
+    /**
+     * Demarshall values from a buffer.
+     *
+     * @param sig The D-Bus signature(s) of the value(s).
+     * @param buf The buffer to demarshall from.
+     * @param ofs The offset into the data buffer to start.
+     * @return The demarshalled value(s).
+     */
+    public Object[] extract(String sig, byte[] buf, int ofs) throws DBusException {
+        return extract(sig, buf, new int[]{0, ofs});
+    }
+
+    /**
+     * Demarshall values from a buffer.
+     *
+     * @param sig The D-Bus signature(s) of the value(s).
+     * @param buf The buffer to demarshall from.
+     * @param ofs An array of two ints, the offset into the signature
+     *            and the offset into the data buffer. These values will be
+     *            updated to the start of the next value ofter demarshalling.
+     * @return The demarshalled value(s).
+     */
+    public Object[] extract(String sig, byte[] buf, int[] ofs) throws DBusException {
+        if (Debug.debug)
+            Debug.print(Debug.VERBOSE, "extract(" + sig + ",#" + buf.length + ", {" + ofs[0] + "," + ofs[1] + "}");
+        Vector<Object> rv = new Vector<Object>();
+        byte[] sigb = sig.getBytes();
+        for (int[] i = ofs; i[0] < sigb.length; i[0]++) {
+            rv.add(extractone(sigb, buf, i, false));
+        }
+        return rv.toArray();
+    }
+
+    /**
+     * Returns the Bus ID that sent the message.
+     */
+    public String getSource() {
+        return (String) headers.get(HeaderField.SENDER);
+    }
+
+    /**
+     * Returns the destination of the message.
+     */
+    public String getDestination() {
+        return (String) headers.get(HeaderField.DESTINATION);
+    }
+
+    /**
+     * Returns the interface of the message.
+     */
+    public String getInterface() {
+        return (String) headers.get(HeaderField.INTERFACE);
+    }
+
+    /**
+     * Returns the object path of the message.
+     */
+    public String getPath() {
+        Object o = headers.get(HeaderField.PATH);
+        if (null == o) return null;
+        return o.toString();
+    }
+
+    /**
+     * Returns the member name or error name this message represents.
+     */
+    public String getName() {
+        if (this instanceof Error)
+            return (String) headers.get(HeaderField.ERROR_NAME);
+        else
+            return (String) headers.get(HeaderField.MEMBER);
+    }
+
+    /**
+     * Returns the dbus signature of the parameters.
+     */
+    public String getSig() {
+        return (String) headers.get(HeaderField.SIGNATURE);
+    }
+
+    /**
+     * Returns the message flags.
+     */
+    public int getFlags() {
+        return flags;
+    }
+
+    /**
+     * Returns the message serial ID (unique for this connection)
+     *
+     * @return the message serial.
+     */
+    public long getSerial() {
+        return serial;
+    }
+
+    /**
+     * If this is a reply to a message, this returns its serial.
+     *
+     * @return The reply serial, or 0 if it is not a reply.
+     */
+    public long getReplySerial() {
+        Number l = (Number) headers.get(HeaderField.REPLY_SERIAL);
+        if (null == l) return 0;
+        return l.longValue();
+    }
+
+    /**
+     * Parses and returns the parameters to this message as an Object array.
+     */
+    public Object[] getParameters() throws DBusException {
+        if (null == args && null != body) {
+            String sig = (String) headers.get(HeaderField.SIGNATURE);
+            if (null != sig && 0 != body.length) {
+                args = extract(sig, body, 0);
+            } else args = new Object[0];
+        }
+        return args;
+    }
+
+    protected void setArgs(Object[] args) {
+        this.args = args;
+    }
+
+    /**
+     * Warning, do not use this method unless you really know what you are doing.
+     */
+    public void setSource(String source) throws DBusException {
+        if (null != body) {
+            wiredata = new byte[BUFFERINCREMENT][];
+            bufferuse = 0;
+            bytecounter = 0;
+            preallocate(12);
+            append("yyyyuu", big ? Endian.BIG : Endian.LITTLE, type, flags, protover, bodylen, serial);
+            headers.put(HeaderField.SENDER, source);
+            Object[][] newhead = new Object[headers.size()][];
+            int i = 0;
+            for (Byte b : headers.keySet()) {
+                newhead[i] = new Object[2];
+                newhead[i][0] = b;
+                newhead[i][1] = headers.get(b);
+                i++;
+            }
+            append("a(yv)", (Object) newhead);
+            pad((byte) 8);
+            appendBytes(body);
+        }
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/MessageReader.java b/federation/sssd/src/main/java/org/freedesktop/dbus/MessageReader.java
new file mode 100644
index 0000000..4dbea00
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/MessageReader.java
@@ -0,0 +1,194 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import cx.ath.matthew.debug.Debug;
+import cx.ath.matthew.utils.Hexdump;
+import org.freedesktop.dbus.exceptions.DBusException;
+import org.freedesktop.dbus.exceptions.MessageProtocolVersionException;
+import org.freedesktop.dbus.exceptions.MessageTypeException;
+
+import java.io.BufferedInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.SocketTimeoutException;
+import java.text.MessageFormat;
+
+import static org.freedesktop.dbus.Gettext.getString;
+
+public class MessageReader {
+    private InputStream in;
+    private byte[] buf = null;
+    private byte[] tbuf = null;
+    private byte[] header = null;
+    private byte[] body = null;
+    private int[] len = new int[4];
+
+    public MessageReader(InputStream in) {
+        this.in = new BufferedInputStream(in);
+    }
+
+    public Message readMessage() throws IOException, DBusException {
+        int rv;
+      /* Read the 12 byte fixed header, retrying as neccessary */
+        if (null == buf) {
+            buf = new byte[12];
+            len[0] = 0;
+        }
+        if (len[0] < 12) {
+            try {
+                rv = in.read(buf, len[0], 12 - len[0]);
+            } catch (SocketTimeoutException STe) {
+                return null;
+            }
+            if (-1 == rv) throw new EOFException(getString("transportReturnedEOF"));
+            len[0] += rv;
+        }
+        if (len[0] == 0) return null;
+        if (len[0] < 12) {
+            if (Debug.debug) Debug.print(Debug.DEBUG, "Only got " + len[0] + " of 12 bytes of header");
+            return null;
+        }
+
+      /* Parse the details from the header */
+        byte endian = buf[0];
+        byte type = buf[1];
+        byte protover = buf[3];
+        if (protover > Message.PROTOCOL) {
+            buf = null;
+            throw new MessageProtocolVersionException(MessageFormat.format(getString("protocolVersionUnsupported"), new Object[]{protover}));
+        }
+
+      /* Read the length of the variable header */
+        if (null == tbuf) {
+            tbuf = new byte[4];
+            len[1] = 0;
+        }
+        if (len[1] < 4) {
+            try {
+                rv = in.read(tbuf, len[1], 4 - len[1]);
+            } catch (SocketTimeoutException STe) {
+                return null;
+            }
+            if (-1 == rv) throw new EOFException(getString("transportReturnedEOF"));
+            len[1] += rv;
+        }
+        if (len[1] < 4) {
+            if (Debug.debug) Debug.print(Debug.DEBUG, "Only got " + len[1] + " of 4 bytes of header");
+            return null;
+        }
+
+      /* Parse the variable header length */
+        int headerlen = 0;
+        if (null == header) {
+            headerlen = (int) Message.demarshallint(tbuf, 0, endian, 4);
+            if (0 != headerlen % 8)
+                headerlen += 8 - (headerlen % 8);
+        } else
+            headerlen = header.length - 8;
+
+      /* Read the variable header */
+        if (null == header) {
+            header = new byte[headerlen + 8];
+            System.arraycopy(tbuf, 0, header, 0, 4);
+            len[2] = 0;
+        }
+        if (len[2] < headerlen) {
+            try {
+                rv = in.read(header, 8 + len[2], headerlen - len[2]);
+            } catch (SocketTimeoutException STe) {
+                return null;
+            }
+            if (-1 == rv) throw new EOFException(getString("transportReturnedEOF"));
+            len[2] += rv;
+        }
+        if (len[2] < headerlen) {
+            if (Debug.debug) Debug.print(Debug.DEBUG, "Only got " + len[2] + " of " + headerlen + " bytes of header");
+            return null;
+        }
+
+      /* Read the body */
+        int bodylen = 0;
+        if (null == body) bodylen = (int) Message.demarshallint(buf, 4, endian, 4);
+        if (null == body) {
+            body = new byte[bodylen];
+            len[3] = 0;
+        }
+        if (len[3] < body.length) {
+            try {
+                rv = in.read(body, len[3], body.length - len[3]);
+            } catch (SocketTimeoutException STe) {
+                return null;
+            }
+            if (-1 == rv) throw new EOFException(getString("transportReturnedEOF"));
+            len[3] += rv;
+        }
+        if (len[3] < body.length) {
+            if (Debug.debug) Debug.print(Debug.DEBUG, "Only got " + len[3] + " of " + body.length + " bytes of body");
+            return null;
+        }
+
+        Message m;
+        switch (type) {
+            case Message.MessageType.METHOD_CALL:
+                m = new MethodCall();
+                break;
+            case Message.MessageType.METHOD_RETURN:
+                m = new MethodReturn();
+                break;
+            case Message.MessageType.SIGNAL:
+                m = new DBusSignal();
+                break;
+            case Message.MessageType.ERROR:
+                m = new Error();
+                break;
+            default:
+                throw new MessageTypeException(MessageFormat.format(getString("messageTypeUnsupported"), new Object[]{type}));
+        }
+        if (Debug.debug) {
+            Debug.print(Debug.VERBOSE, Hexdump.format(buf));
+            Debug.print(Debug.VERBOSE, Hexdump.format(tbuf));
+            Debug.print(Debug.VERBOSE, Hexdump.format(header));
+            Debug.print(Debug.VERBOSE, Hexdump.format(body));
+        }
+        try {
+            m.populate(buf, header, body);
+        } catch (DBusException DBe) {
+            if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBe);
+            buf = null;
+            tbuf = null;
+            body = null;
+            header = null;
+            throw DBe;
+        } catch (RuntimeException Re) {
+            if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, Re);
+            buf = null;
+            tbuf = null;
+            body = null;
+            header = null;
+            throw Re;
+        }
+        if (Debug.debug) {
+            Debug.print(Debug.INFO, "=> " + m);
+        }
+        buf = null;
+        tbuf = null;
+        body = null;
+        header = null;
+        return m;
+    }
+
+    public void close() throws IOException {
+        if (Debug.debug) Debug.print(Debug.INFO, "Closing Message Reader");
+        in.close();
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/MessageWriter.java b/federation/sssd/src/main/java/org/freedesktop/dbus/MessageWriter.java
new file mode 100644
index 0000000..45e8cb7
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/MessageWriter.java
@@ -0,0 +1,67 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import cx.ath.matthew.debug.Debug;
+import cx.ath.matthew.unix.USOutputStream;
+import cx.ath.matthew.utils.Hexdump;
+
+import java.io.BufferedOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class MessageWriter {
+    private OutputStream out;
+    private boolean isunix;
+
+    public MessageWriter(OutputStream out) {
+        this.out = out;
+        this.isunix = false;
+        try {
+            if (out instanceof USOutputStream)
+                this.isunix = true;
+        } catch (Throwable t) {
+        }
+        if (!this.isunix)
+            this.out = new BufferedOutputStream(this.out);
+    }
+
+    public void writeMessage(Message m) throws IOException {
+        if (Debug.debug) {
+            Debug.print(Debug.INFO, "<= " + m);
+        }
+        if (null == m) return;
+        if (null == m.getWireData()) {
+            if (Debug.debug) Debug.print(Debug.WARN, "Message " + m + " wire-data was null!");
+            return;
+        }
+        if (isunix) {
+            if (Debug.debug) {
+                Debug.print(Debug.DEBUG, "Writing all " + m.getWireData().length + " buffers simultaneously to Unix Socket");
+                for (byte[] buf : m.getWireData())
+                    Debug.print(Debug.VERBOSE, "(" + buf + "):" + (null == buf ? "" : Hexdump.format(buf)));
+            }
+            ((USOutputStream) out).write(m.getWireData());
+        } else
+            for (byte[] buf : m.getWireData()) {
+                if (Debug.debug)
+                    Debug.print(Debug.VERBOSE, "(" + buf + "):" + (null == buf ? "" : Hexdump.format(buf)));
+                if (null == buf) break;
+                out.write(buf);
+            }
+        out.flush();
+    }
+
+    public void close() throws IOException {
+        if (Debug.debug) Debug.print(Debug.INFO, "Closing Message Writer");
+        out.close();
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/MethodCall.java b/federation/sssd/src/main/java/org/freedesktop/dbus/MethodCall.java
new file mode 100644
index 0000000..72242cc
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/MethodCall.java
@@ -0,0 +1,137 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import cx.ath.matthew.debug.Debug;
+import cx.ath.matthew.utils.Hexdump;
+import org.freedesktop.dbus.exceptions.DBusException;
+import org.freedesktop.dbus.exceptions.MessageFormatException;
+
+import java.util.Vector;
+
+import static org.freedesktop.dbus.Gettext.getString;
+
+public class MethodCall extends Message {
+    MethodCall() {
+    }
+
+    public MethodCall(String dest, String path, String iface, String member, byte flags, String sig, Object... args) throws DBusException {
+        this(null, dest, path, iface, member, flags, sig, args);
+    }
+
+    public MethodCall(String source, String dest, String path, String iface, String member, byte flags, String sig, Object... args) throws DBusException {
+        super(Message.Endian.BIG, Message.MessageType.METHOD_CALL, flags);
+
+        if (null == member || null == path)
+            throw new MessageFormatException(getString("missingDestinationPathFunction"));
+        headers.put(Message.HeaderField.PATH, path);
+        headers.put(Message.HeaderField.MEMBER, member);
+
+        Vector<Object> hargs = new Vector<Object>();
+
+        hargs.add(new Object[]{Message.HeaderField.PATH, new Object[]{ArgumentType.OBJECT_PATH_STRING, path}});
+
+        if (null != source) {
+            headers.put(Message.HeaderField.SENDER, source);
+            hargs.add(new Object[]{Message.HeaderField.SENDER, new Object[]{ArgumentType.STRING_STRING, source}});
+        }
+
+        if (null != dest) {
+            headers.put(Message.HeaderField.DESTINATION, dest);
+            hargs.add(new Object[]{Message.HeaderField.DESTINATION, new Object[]{ArgumentType.STRING_STRING, dest}});
+        }
+
+        if (null != iface) {
+            hargs.add(new Object[]{Message.HeaderField.INTERFACE, new Object[]{ArgumentType.STRING_STRING, iface}});
+            headers.put(Message.HeaderField.INTERFACE, iface);
+        }
+
+        hargs.add(new Object[]{Message.HeaderField.MEMBER, new Object[]{ArgumentType.STRING_STRING, member}});
+
+        if (null != sig) {
+            if (Debug.debug) Debug.print(Debug.DEBUG, "Appending arguments with signature: " + sig);
+            hargs.add(new Object[]{Message.HeaderField.SIGNATURE, new Object[]{ArgumentType.SIGNATURE_STRING, sig}});
+            headers.put(Message.HeaderField.SIGNATURE, sig);
+            setArgs(args);
+        }
+
+        byte[] blen = new byte[4];
+        appendBytes(blen);
+        append("ua(yv)", serial, hargs.toArray());
+        pad((byte) 8);
+
+        long c = bytecounter;
+        if (null != sig) append(sig, args);
+        if (Debug.debug)
+            Debug.print(Debug.DEBUG, "Appended body, type: " + sig + " start: " + c + " end: " + bytecounter + " size: " + (bytecounter - c));
+        marshallint(bytecounter - c, blen, 0, 4);
+        if (Debug.debug) Debug.print("marshalled size (" + blen + "): " + Hexdump.format(blen));
+    }
+
+    private static long REPLY_WAIT_TIMEOUT = 20000;
+
+    /**
+     * Set the default timeout for method calls.
+     * Default is 20s.
+     *
+     * @param timeout New timeout in ms.
+     */
+    public static void setDefaultTimeout(long timeout) {
+        REPLY_WAIT_TIMEOUT = timeout;
+    }
+
+    Message reply = null;
+
+    public synchronized boolean hasReply() {
+        return null != reply;
+    }
+
+    /**
+     * Block (if neccessary) for a reply.
+     *
+     * @param timeout The length of time to block before timing out (ms).
+     * @return The reply to this MethodCall, or null if a timeout happens.
+     */
+    public synchronized Message getReply(long timeout) {
+        if (Debug.debug) Debug.print(Debug.VERBOSE, "Blocking on " + this);
+        if (null != reply) return reply;
+        try {
+            wait(timeout);
+            return reply;
+        } catch (InterruptedException Ie) {
+            return reply;
+        }
+    }
+
+    /**
+     * Block (if neccessary) for a reply.
+     * Default timeout is 20s, or can be configured with setDefaultTimeout()
+     *
+     * @return The reply to this MethodCall, or null if a timeout happens.
+     */
+    public synchronized Message getReply() {
+        if (Debug.debug) Debug.print(Debug.VERBOSE, "Blocking on " + this);
+        if (null != reply) return reply;
+        try {
+            wait(REPLY_WAIT_TIMEOUT);
+            return reply;
+        } catch (InterruptedException Ie) {
+            return reply;
+        }
+    }
+
+    protected synchronized void setReply(Message reply) {
+        if (Debug.debug) Debug.print(Debug.VERBOSE, "Setting reply to " + this + " to " + reply);
+        this.reply = reply;
+        notifyAll();
+    }
+
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/MethodReturn.java b/federation/sssd/src/main/java/org/freedesktop/dbus/MethodReturn.java
new file mode 100644
index 0000000..35f4d0d
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/MethodReturn.java
@@ -0,0 +1,77 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.dbus.exceptions.DBusException;
+
+import java.util.Vector;
+
+public class MethodReturn extends Message {
+    MethodReturn() {
+    }
+
+    public MethodReturn(String dest, long replyserial, String sig, Object... args) throws DBusException {
+        this(null, dest, replyserial, sig, args);
+    }
+
+    public MethodReturn(String source, String dest, long replyserial, String sig, Object... args) throws DBusException {
+        super(Message.Endian.BIG, Message.MessageType.METHOD_RETURN, (byte) 0);
+
+        headers.put(Message.HeaderField.REPLY_SERIAL, replyserial);
+
+        Vector<Object> hargs = new Vector<Object>();
+        hargs.add(new Object[]{Message.HeaderField.REPLY_SERIAL, new Object[]{ArgumentType.UINT32_STRING, replyserial}});
+
+        if (null != source) {
+            headers.put(Message.HeaderField.SENDER, source);
+            hargs.add(new Object[]{Message.HeaderField.SENDER, new Object[]{ArgumentType.STRING_STRING, source}});
+        }
+
+        if (null != dest) {
+            headers.put(Message.HeaderField.DESTINATION, dest);
+            hargs.add(new Object[]{Message.HeaderField.DESTINATION, new Object[]{ArgumentType.STRING_STRING, dest}});
+        }
+
+        if (null != sig) {
+            hargs.add(new Object[]{Message.HeaderField.SIGNATURE, new Object[]{ArgumentType.SIGNATURE_STRING, sig}});
+            headers.put(Message.HeaderField.SIGNATURE, sig);
+            setArgs(args);
+        }
+
+        byte[] blen = new byte[4];
+        appendBytes(blen);
+        append("ua(yv)", serial, hargs.toArray());
+        pad((byte) 8);
+
+        long c = bytecounter;
+        if (null != sig) append(sig, args);
+        marshallint(bytecounter - c, blen, 0, 4);
+    }
+
+    public MethodReturn(MethodCall mc, String sig, Object... args) throws DBusException {
+        this(null, mc, sig, args);
+    }
+
+    public MethodReturn(String source, MethodCall mc, String sig, Object... args) throws DBusException {
+        this(source, mc.getSource(), mc.getSerial(), sig, args);
+        this.call = mc;
+    }
+
+    MethodCall call;
+
+    public MethodCall getCall() {
+        return call;
+    }
+
+    protected void setCall(MethodCall call) {
+        this.call = call;
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/MethodTuple.java b/federation/sssd/src/main/java/org/freedesktop/dbus/MethodTuple.java
new file mode 100644
index 0000000..d135714
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/MethodTuple.java
@@ -0,0 +1,37 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import cx.ath.matthew.debug.Debug;
+
+class MethodTuple {
+    String name;
+    String sig;
+
+    public MethodTuple(String name, String sig) {
+        this.name = name;
+        if (null != sig)
+            this.sig = sig;
+        else
+            this.sig = "";
+        if (Debug.debug) Debug.print(Debug.VERBOSE, "new MethodTuple(" + this.name + ", " + this.sig + ")");
+    }
+
+    public boolean equals(Object o) {
+        return o.getClass().equals(MethodTuple.class)
+                && ((MethodTuple) o).name.equals(this.name)
+                && ((MethodTuple) o).sig.equals(this.sig);
+    }
+
+    public int hashCode() {
+        return name.hashCode() + sig.hashCode();
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/ObjectPath.java b/federation/sssd/src/main/java/org/freedesktop/dbus/ObjectPath.java
new file mode 100644
index 0000000..5ea1158
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/ObjectPath.java
@@ -0,0 +1,22 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+class ObjectPath extends Path {
+    public String source;
+
+    //   public DBusConnection conn;
+    public ObjectPath(String source, String path/*, DBusConnection conn*/) {
+        super(path);
+        this.source = source;
+        //    this.conn = conn;
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/ObjectTree.java b/federation/sssd/src/main/java/org/freedesktop/dbus/ObjectTree.java
new file mode 100644
index 0000000..0332e6a
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/ObjectTree.java
@@ -0,0 +1,158 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import cx.ath.matthew.debug.Debug;
+
+import java.util.regex.Pattern;
+
+/**
+ * Keeps track of the exported objects for introspection data
+ */
+class ObjectTree {
+    class TreeNode {
+        String name;
+        ExportedObject object;
+        String data;
+        TreeNode right;
+        TreeNode down;
+
+        public TreeNode(String name) {
+            this.name = name;
+        }
+
+        public TreeNode(String name, ExportedObject object, String data) {
+            this.name = name;
+            this.object = object;
+            this.data = data;
+        }
+    }
+
+    private TreeNode root;
+
+    public ObjectTree() {
+        root = new TreeNode("");
+    }
+
+    public static final Pattern slashpattern = Pattern.compile("/");
+
+    private TreeNode recursiveFind(TreeNode current, String path) {
+        if ("/".equals(path)) return current;
+        String[] elements = path.split("/", 2);
+        // this is us or a parent node
+        if (path.startsWith(current.name)) {
+            // this is us
+            if (path.equals(current.name)) {
+                return current;
+            }
+            // recurse down
+            else {
+                if (current.down == null)
+                    return null;
+                else return recursiveFind(current.down, elements[1]);
+            }
+        } else if (current.right == null) {
+            return null;
+        } else if (0 > current.right.name.compareTo(elements[0])) {
+            return null;
+        }
+        // recurse right
+        else {
+            return recursiveFind(current.right, path);
+        }
+    }
+
+    private TreeNode recursiveAdd(TreeNode current, String path, ExportedObject object, String data) {
+        String[] elements = slashpattern.split(path, 2);
+        // this is us or a parent node
+        if (path.startsWith(current.name)) {
+            // this is us
+            if (1 == elements.length || "".equals(elements[1])) {
+                current.object = object;
+                current.data = data;
+            }
+            // recurse down
+            else {
+                if (current.down == null) {
+                    String[] el = elements[1].split("/", 2);
+                    current.down = new TreeNode(el[0]);
+                }
+                current.down = recursiveAdd(current.down, elements[1], object, data);
+            }
+        }
+        // need to create a new sub-tree on the end
+        else if (current.right == null) {
+            current.right = new TreeNode(elements[0]);
+            current.right = recursiveAdd(current.right, path, object, data);
+        }
+        // need to insert here
+        else if (0 > current.right.name.compareTo(elements[0])) {
+            TreeNode t = new TreeNode(elements[0]);
+            t.right = current.right;
+            current.right = t;
+            current.right = recursiveAdd(current.right, path, object, data);
+        }
+        // recurse right
+        else {
+            current.right = recursiveAdd(current.right, path, object, data);
+        }
+        return current;
+    }
+
+    public void add(String path, ExportedObject object, String data) {
+        if (Debug.debug) Debug.print(Debug.DEBUG, "Adding " + path + " to object tree");
+        root = recursiveAdd(root, path, object, data);
+    }
+
+    public void remove(String path) {
+        if (Debug.debug) Debug.print(Debug.DEBUG, "Removing " + path + " from object tree");
+        TreeNode t = recursiveFind(root, path);
+        t.object = null;
+        t.data = null;
+    }
+
+    public String Introspect(String path) {
+        TreeNode t = recursiveFind(root, path);
+        if (null == t) return null;
+        StringBuilder sb = new StringBuilder();
+        sb.append("<node name=\"");
+        sb.append(path);
+        sb.append("\">\n");
+        if (null != t.data) sb.append(t.data);
+        t = t.down;
+        while (null != t) {
+            sb.append("<node name=\"");
+            sb.append(t.name);
+            sb.append("\"/>\n");
+            t = t.right;
+        }
+        sb.append("</node>");
+        return sb.toString();
+    }
+
+    private String recursivePrint(TreeNode current) {
+        String s = "";
+        if (null != current) {
+            s += current.name;
+            if (null != current.object)
+                s += "*";
+            if (null != current.down)
+                s += "/{" + recursivePrint(current.down) + "}";
+            if (null != current.right)
+                s += ", " + recursivePrint(current.right);
+        }
+        return s;
+    }
+
+    public String toString() {
+        return recursivePrint(root);
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/Path.java b/federation/sssd/src/main/java/org/freedesktop/dbus/Path.java
new file mode 100644
index 0000000..91a5a6d
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/Path.java
@@ -0,0 +1,39 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+public class Path implements Comparable<Path> {
+    protected String path;
+
+    public Path(String path) {
+        this.path = path;
+    }
+
+    public String getPath() {
+        return path;
+    }
+
+    public String toString() {
+        return path;
+    }
+
+    public boolean equals(Object other) {
+        return (other instanceof Path) && path.equals(((Path) other).path);
+    }
+
+    public int hashCode() {
+        return path.hashCode();
+    }
+
+    public int compareTo(Path that) {
+        return path.compareTo(that.path);
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/Position.java b/federation/sssd/src/main/java/org/freedesktop/dbus/Position.java
new file mode 100644
index 0000000..ed0bb11
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/Position.java
@@ -0,0 +1,29 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Position annotation, to annotate Struct fields
+ * to be sent over DBus.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface Position {
+    /**
+     * The order of this field in the Struct.
+     */
+    int value();
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/RemoteInvocationHandler.java b/federation/sssd/src/main/java/org/freedesktop/dbus/RemoteInvocationHandler.java
new file mode 100644
index 0000000..f6b7867
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/RemoteInvocationHandler.java
@@ -0,0 +1,187 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import cx.ath.matthew.debug.Debug;
+import org.freedesktop.DBus;
+import org.freedesktop.dbus.exceptions.DBusException;
+import org.freedesktop.dbus.exceptions.DBusExecutionException;
+import org.freedesktop.dbus.exceptions.NotConnected;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.lang.reflect.Type;
+import java.text.MessageFormat;
+import java.util.Arrays;
+
+import static org.freedesktop.dbus.Gettext.getString;
+
+class RemoteInvocationHandler implements InvocationHandler {
+    public static final int CALL_TYPE_SYNC = 0;
+    public static final int CALL_TYPE_ASYNC = 1;
+    public static final int CALL_TYPE_CALLBACK = 2;
+
+    public static Object convertRV(String sig, Object[] rp, Method m, AbstractConnection conn) throws DBusException {
+        Class<? extends Object> c = m.getReturnType();
+
+        if (null == rp) {
+            if (null == c || Void.TYPE.equals(c)) return null;
+            else throw new DBusExecutionException(getString("voidReturnType"));
+        } else {
+            try {
+                if (Debug.debug)
+                    Debug.print(Debug.VERBOSE, "Converting return parameters from " + Arrays.deepToString(rp) + " to type " + m.getGenericReturnType());
+                rp = Marshalling.deSerializeParameters(rp,
+                        new Type[]{m.getGenericReturnType()}, conn);
+            } catch (Exception e) {
+                if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
+                throw new DBusExecutionException(MessageFormat.format(getString("invalidReturnType"), new Object[]{e.getMessage()}));
+            }
+        }
+
+        switch (rp.length) {
+            case 0:
+                if (null == c || Void.TYPE.equals(c))
+                    return null;
+                else throw new DBusExecutionException(getString("voidReturnType"));
+            case 1:
+                return rp[0];
+            default:
+
+                // check we are meant to return multiple values
+                if (!Tuple.class.isAssignableFrom(c))
+                    throw new DBusExecutionException(getString("tupleReturnType"));
+
+                Constructor<? extends Object> cons = c.getConstructors()[0];
+                try {
+                    return cons.newInstance(rp);
+                } catch (Exception e) {
+                    if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
+                    throw new DBusException(e.getMessage());
+                }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public static Object executeRemoteMethod(RemoteObject ro, Method m, AbstractConnection conn, int syncmethod, CallbackHandler callback, Object... args) throws DBusExecutionException {
+        Type[] ts = m.getGenericParameterTypes();
+        String sig = null;
+        if (ts.length > 0) try {
+            sig = Marshalling.getDBusType(ts);
+            args = Marshalling.convertParameters(args, ts, conn);
+        } catch (DBusException DBe) {
+            throw new DBusExecutionException(getString("contructDBusTypeFailure") + DBe.getMessage());
+        }
+        MethodCall call;
+        byte flags = 0;
+        if (!ro.autostart) flags |= Message.Flags.NO_AUTO_START;
+        if (syncmethod == CALL_TYPE_ASYNC) flags |= Message.Flags.ASYNC;
+        if (m.isAnnotationPresent(DBus.Method.NoReply.class)) flags |= Message.Flags.NO_REPLY_EXPECTED;
+        try {
+            String name;
+            if (m.isAnnotationPresent(DBusMemberName.class))
+                name = m.getAnnotation(DBusMemberName.class).value();
+            else
+                name = m.getName();
+            if (null == ro.iface)
+                call = new MethodCall(ro.busname, ro.objectpath, null, name, flags, sig, args);
+            else {
+                if (null != ro.iface.getAnnotation(DBusInterfaceName.class)) {
+                    call = new MethodCall(ro.busname, ro.objectpath, ro.iface.getAnnotation(DBusInterfaceName.class).value(), name, flags, sig, args);
+                } else
+                    call = new MethodCall(ro.busname, ro.objectpath, AbstractConnection.dollar_pattern.matcher(ro.iface.getName()).replaceAll("."), name, flags, sig, args);
+            }
+        } catch (DBusException DBe) {
+            if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBe);
+            throw new DBusExecutionException(getString("constructOutgoingMethodCallFailure") + DBe.getMessage());
+        }
+        if (null == conn.outgoing) throw new NotConnected(getString("notConnected"));
+
+        switch (syncmethod) {
+            case CALL_TYPE_ASYNC:
+                conn.queueOutgoing(call);
+                return new DBusAsyncReply(call, m, conn);
+            case CALL_TYPE_CALLBACK:
+                synchronized (conn.pendingCallbacks) {
+                    if (Debug.debug) Debug.print(Debug.VERBOSE, "Queueing Callback " + callback + " for " + call);
+                    conn.pendingCallbacks.put(call, callback);
+                    conn.pendingCallbackReplys.put(call, new DBusAsyncReply(call, m, conn));
+                }
+                conn.queueOutgoing(call);
+                return null;
+            case CALL_TYPE_SYNC:
+                conn.queueOutgoing(call);
+                break;
+        }
+
+        // get reply
+        if (m.isAnnotationPresent(DBus.Method.NoReply.class)) return null;
+
+        Message reply = call.getReply();
+        if (null == reply) throw new DBus.Error.NoReply(getString("notReplyWithSpecifiedTime"));
+
+        if (reply instanceof Error)
+            ((Error) reply).throwException();
+
+        try {
+            return convertRV(reply.getSig(), reply.getParameters(), m, conn);
+        } catch (DBusException e) {
+            if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
+            throw new DBusExecutionException(e.getMessage());
+        }
+    }
+
+    AbstractConnection conn;
+    RemoteObject remote;
+
+    public RemoteInvocationHandler(AbstractConnection conn, RemoteObject remote) {
+        this.remote = remote;
+        this.conn = conn;
+    }
+
+    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+        if (method.getName().equals("isRemote")) return true;
+        else if (method.getName().equals("clone")) return null;
+        else if (method.getName().equals("equals")) {
+            try {
+                if (1 == args.length)
+                    return new Boolean(remote.equals(((RemoteInvocationHandler) Proxy.getInvocationHandler(args[0])).remote));
+            } catch (IllegalArgumentException IAe) {
+                return Boolean.FALSE;
+            }
+        } else if (method.getName().equals("finalize")) return null;
+        else if (method.getName().equals("getClass")) return DBusInterface.class;
+        else if (method.getName().equals("hashCode")) return remote.hashCode();
+        else if (method.getName().equals("notify")) {
+            remote.notify();
+            return null;
+        } else if (method.getName().equals("notifyAll")) {
+            remote.notifyAll();
+            return null;
+        } else if (method.getName().equals("wait")) {
+            if (0 == args.length) remote.wait();
+            else if (1 == args.length
+                    && args[0] instanceof Long) remote.wait((Long) args[0]);
+            else if (2 == args.length
+                    && args[0] instanceof Long
+                    && args[1] instanceof Integer)
+                remote.wait((Long) args[0], (Integer) args[1]);
+            if (args.length <= 2)
+                return null;
+        } else if (method.getName().equals("toString"))
+            return remote.toString();
+
+        return executeRemoteMethod(remote, method, conn, CALL_TYPE_SYNC, null, args);
+    }
+}
+
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/RemoteObject.java b/federation/sssd/src/main/java/org/freedesktop/dbus/RemoteObject.java
new file mode 100644
index 0000000..c157d12
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/RemoteObject.java
@@ -0,0 +1,67 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+class RemoteObject {
+    String busname;
+    String objectpath;
+    Class<? extends DBusInterface> iface;
+    boolean autostart;
+
+    public RemoteObject(String busname, String objectpath, Class<? extends DBusInterface> iface, boolean autostart) {
+        this.busname = busname;
+        this.objectpath = objectpath;
+        this.iface = iface;
+        this.autostart = autostart;
+    }
+
+    public boolean equals(Object o) {
+        if (!(o instanceof RemoteObject)) return false;
+        RemoteObject them = (RemoteObject) o;
+
+        if (!them.objectpath.equals(this.objectpath)) return false;
+
+        if (null == this.busname && null != them.busname) return false;
+        if (null != this.busname && null == them.busname) return false;
+        if (null != them.busname && !them.busname.equals(this.busname)) return false;
+
+        if (null == this.iface && null != them.iface) return false;
+        if (null != this.iface && null == them.iface) return false;
+        if (null != them.iface && !them.iface.equals(this.iface)) return false;
+
+        return true;
+    }
+
+    public int hashCode() {
+        return (null == busname ? 0 : busname.hashCode()) + objectpath.hashCode() +
+                (null == iface ? 0 : iface.hashCode());
+    }
+
+    public boolean autoStarting() {
+        return autostart;
+    }
+
+    public String getBusName() {
+        return busname;
+    }
+
+    public String getObjectPath() {
+        return objectpath;
+    }
+
+    public Class<? extends DBusInterface> getInterface() {
+        return iface;
+    }
+
+    public String toString() {
+        return busname + ":" + objectpath + ":" + iface;
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/SignalTuple.java b/federation/sssd/src/main/java/org/freedesktop/dbus/SignalTuple.java
new file mode 100644
index 0000000..29ec987
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/SignalTuple.java
@@ -0,0 +1,51 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+class SignalTuple {
+    String type;
+    String name;
+    String object;
+    String source;
+
+    public SignalTuple(String type, String name, String object, String source) {
+        this.type = type;
+        this.name = name;
+        this.object = object;
+        this.source = source;
+    }
+
+    public boolean equals(Object o) {
+        if (!(o instanceof SignalTuple)) return false;
+        SignalTuple other = (SignalTuple) o;
+        if (null == this.type && null != other.type) return false;
+        if (null != this.type && !this.type.equals(other.type)) return false;
+        if (null == this.name && null != other.name) return false;
+        if (null != this.name && !this.name.equals(other.name)) return false;
+        if (null == this.object && null != other.object) return false;
+        if (null != this.object && !this.object.equals(other.object)) return false;
+        if (null == this.source && null != other.source) return false;
+        if (null != this.source && !this.source.equals(other.source)) return false;
+        return true;
+    }
+
+    public int hashCode() {
+        return (null == type ? 0 : type.hashCode())
+                + (null == name ? 0 : name.hashCode())
+                + (null == source ? 0 : source.hashCode())
+                + (null == object ? 0 : object.hashCode());
+    }
+
+    public String toString() {
+        return "SignalTuple(" + type + "," + name + "," + object + "," + source + ")";
+    }
+}
+
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/StrongReference.java b/federation/sssd/src/main/java/org/freedesktop/dbus/StrongReference.java
new file mode 100644
index 0000000..d5358ec
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/StrongReference.java
@@ -0,0 +1,42 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * An alternative to a WeakReference when you don't want
+ * that behaviour.
+ */
+public class StrongReference<T> extends WeakReference<T> {
+    T referant;
+
+    public StrongReference(T referant) {
+        super(referant);
+        this.referant = referant;
+    }
+
+    public void clear() {
+        referant = null;
+    }
+
+    public boolean enqueue() {
+        return false;
+    }
+
+    public T get() {
+        return referant;
+    }
+
+    public boolean isEnqueued() {
+        return false;
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/Struct.java b/federation/sssd/src/main/java/org/freedesktop/dbus/Struct.java
new file mode 100644
index 0000000..18667e5
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/Struct.java
@@ -0,0 +1,23 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+/**
+ * This class should be extended to create Structs.
+ * Any such class may be sent over DBus to a method which takes a Struct.
+ * All fields in the Struct which you wish to be serialized and sent to the
+ * remote method should be annotated with the org.freedesktop.dbus.Position
+ * annotation, in the order they should appear in to Struct to DBus.
+ */
+public abstract class Struct extends Container {
+    public Struct() {
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/Transport.java b/federation/sssd/src/main/java/org/freedesktop/dbus/Transport.java
new file mode 100644
index 0000000..1745bcf
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/Transport.java
@@ -0,0 +1,835 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import cx.ath.matthew.debug.Debug;
+import cx.ath.matthew.unix.UnixSocket;
+import cx.ath.matthew.unix.UnixSocketAddress;
+import cx.ath.matthew.utils.Hexdump;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.lang.reflect.Method;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.text.Collator;
+import java.text.ParseException;
+import java.util.Arrays;
+import java.util.Random;
+import java.util.Vector;
+
+import static org.freedesktop.dbus.Gettext.getString;
+
+public class Transport {
+    public static class SASL {
+        public static class Command {
+            private int command;
+            private int mechs;
+            private String data;
+            private String response;
+
+            public Command() {
+            }
+
+            public Command(String s) throws IOException {
+                String[] ss = s.split(" ");
+                if (Debug.debug) Debug.print(Debug.VERBOSE, "Creating command from: " + Arrays.toString(ss));
+                if (0 == col.compare(ss[0], "OK")) {
+                    command = COMMAND_OK;
+                    data = ss[1];
+                } else if (0 == col.compare(ss[0], "AUTH")) {
+                    command = COMMAND_AUTH;
+                    if (ss.length > 1) {
+                        if (0 == col.compare(ss[1], "EXTERNAL"))
+                            mechs = AUTH_EXTERNAL;
+                        else if (0 == col.compare(ss[1], "DBUS_COOKIE_SHA1"))
+                            mechs = AUTH_SHA;
+                        else if (0 == col.compare(ss[1], "ANONYMOUS"))
+                            mechs = AUTH_ANON;
+                    }
+                    if (ss.length > 2)
+                        data = ss[2];
+                } else if (0 == col.compare(ss[0], "DATA")) {
+                    command = COMMAND_DATA;
+                    data = ss[1];
+                } else if (0 == col.compare(ss[0], "REJECTED")) {
+                    command = COMMAND_REJECTED;
+                    for (int i = 1; i < ss.length; i++)
+                        if (0 == col.compare(ss[i], "EXTERNAL"))
+                            mechs |= AUTH_EXTERNAL;
+                        else if (0 == col.compare(ss[i], "DBUS_COOKIE_SHA1"))
+                            mechs |= AUTH_SHA;
+                        else if (0 == col.compare(ss[i], "ANONYMOUS"))
+                            mechs |= AUTH_ANON;
+                } else if (0 == col.compare(ss[0], "BEGIN")) {
+                    command = COMMAND_BEGIN;
+                } else if (0 == col.compare(ss[0], "CANCEL")) {
+                    command = COMMAND_CANCEL;
+                } else if (0 == col.compare(ss[0], "ERROR")) {
+                    command = COMMAND_ERROR;
+                    data = ss[1];
+                } else {
+                    throw new IOException(getString("invalidCommand") + ss[0]);
+                }
+                if (Debug.debug) Debug.print(Debug.VERBOSE, "Created command: " + this);
+            }
+
+            public int getCommand() {
+                return command;
+            }
+
+            public int getMechs() {
+                return mechs;
+            }
+
+            public String getData() {
+                return data;
+            }
+
+            public String getResponse() {
+                return response;
+            }
+
+            public void setResponse(String s) {
+                response = s;
+            }
+
+            public String toString() {
+                return "Command(" + command + ", " + mechs + ", " + data + ", " + null + ")";
+            }
+        }
+
+        private static Collator col = Collator.getInstance();
+
+        static {
+            col.setDecomposition(Collator.FULL_DECOMPOSITION);
+            col.setStrength(Collator.PRIMARY);
+        }
+
+        public static final int LOCK_TIMEOUT = 1000;
+        public static final int NEW_KEY_TIMEOUT_SECONDS = 60 * 5;
+        public static final int EXPIRE_KEYS_TIMEOUT_SECONDS = NEW_KEY_TIMEOUT_SECONDS + (60 * 2);
+        public static final int MAX_TIME_TRAVEL_SECONDS = 60 * 5;
+        public static final int COOKIE_TIMEOUT = 240;
+        public static final String COOKIE_CONTEXT = "org_freedesktop_java";
+
+        private String findCookie(String context, String ID) throws IOException {
+            String homedir = System.getProperty("user.home");
+            File f = new File(homedir + "/.dbus-keyrings/" + context);
+            BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream(f)));
+            String s = null;
+            String cookie = null;
+            long now = System.currentTimeMillis() / 1000;
+            while (null != (s = r.readLine())) {
+                String[] line = s.split(" ");
+                long timestamp = Long.parseLong(line[1]);
+                if (line[0].equals(ID) && (!(timestamp < 0 ||
+                        (now + MAX_TIME_TRAVEL_SECONDS) < timestamp ||
+                        (now - EXPIRE_KEYS_TIMEOUT_SECONDS) > timestamp))) {
+                    cookie = line[2];
+                    break;
+                }
+            }
+            r.close();
+            return cookie;
+        }
+
+        private void addCookie(String context, String ID, long timestamp, String cookie) throws IOException {
+            String homedir = System.getProperty("user.home");
+            File keydir = new File(homedir + "/.dbus-keyrings/");
+            File cookiefile = new File(homedir + "/.dbus-keyrings/" + context);
+            File lock = new File(homedir + "/.dbus-keyrings/" + context + ".lock");
+            File temp = new File(homedir + "/.dbus-keyrings/" + context + ".temp");
+
+            // ensure directory exists
+            if (!keydir.exists()) keydir.mkdirs();
+
+            // acquire lock
+            long start = System.currentTimeMillis();
+            while (!lock.createNewFile() && LOCK_TIMEOUT > (System.currentTimeMillis() - start)) ;
+
+            // read old file
+            Vector<String> lines = new Vector<String>();
+            if (cookiefile.exists()) {
+                BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream(cookiefile)));
+                String s = null;
+                while (null != (s = r.readLine())) {
+                    String[] line = s.split(" ");
+                    long time = Long.parseLong(line[1]);
+                    // expire stale cookies
+                    if ((timestamp - time) < COOKIE_TIMEOUT)
+                        lines.add(s);
+                }
+                r.close();
+            }
+
+            // add cookie
+            lines.add(ID + " " + timestamp + " " + cookie);
+
+            // write temp file
+            PrintWriter w = new PrintWriter(new FileOutputStream(temp));
+            for (String l : lines)
+                w.println(l);
+            w.close();
+
+            // atomically move to old file
+            if (!temp.renameTo(cookiefile)) {
+                cookiefile.delete();
+                temp.renameTo(cookiefile);
+            }
+
+            // remove lock
+            lock.delete();
+        }
+
+        /**
+         * Takes the string, encodes it as hex and then turns it into a string again.
+         * No, I don't know why either.
+         */
+        private String stupidlyEncode(String data) {
+            return Hexdump.toHex(data.getBytes()).replaceAll(" ", "");
+        }
+
+        private String stupidlyEncode(byte[] data) {
+            return Hexdump.toHex(data).replaceAll(" ", "");
+        }
+
+        private byte getNibble(char c) {
+            switch (c) {
+                case '0':
+                case '1':
+                case '2':
+                case '3':
+                case '4':
+                case '5':
+                case '6':
+                case '7':
+                case '8':
+                case '9':
+                    return (byte) (c - '0');
+                case 'A':
+                case 'B':
+                case 'C':
+                case 'D':
+                case 'E':
+                case 'F':
+                    return (byte) (c - 'A' + 10);
+                case 'a':
+                case 'b':
+                case 'c':
+                case 'd':
+                case 'e':
+                case 'f':
+                    return (byte) (c - 'a' + 10);
+                default:
+                    return 0;
+            }
+        }
+
+        private String stupidlyDecode(String data) {
+            char[] cs = new char[data.length()];
+            char[] res = new char[cs.length / 2];
+            data.getChars(0, data.length(), cs, 0);
+            for (int i = 0, j = 0; j < res.length; i += 2, j++) {
+                int b = 0;
+                b |= getNibble(cs[i]) << 4;
+                b |= getNibble(cs[i + 1]);
+                res[j] = (char) b;
+            }
+            return new String(res);
+        }
+
+        public static final int MODE_SERVER = 1;
+        public static final int MODE_CLIENT = 2;
+
+        public static final int AUTH_NONE = 0;
+        public static final int AUTH_EXTERNAL = 1;
+        public static final int AUTH_SHA = 2;
+        public static final int AUTH_ANON = 4;
+
+        public static final int COMMAND_AUTH = 1;
+        public static final int COMMAND_DATA = 2;
+        public static final int COMMAND_REJECTED = 3;
+        public static final int COMMAND_OK = 4;
+        public static final int COMMAND_BEGIN = 5;
+        public static final int COMMAND_CANCEL = 6;
+        public static final int COMMAND_ERROR = 7;
+
+        public static final int INITIAL_STATE = 0;
+        public static final int WAIT_DATA = 1;
+        public static final int WAIT_OK = 2;
+        public static final int WAIT_REJECT = 3;
+        public static final int WAIT_AUTH = 4;
+        public static final int WAIT_BEGIN = 5;
+        public static final int AUTHENTICATED = 6;
+        public static final int FAILED = 7;
+
+        public static final int OK = 1;
+        public static final int CONTINUE = 2;
+        public static final int ERROR = 3;
+        public static final int REJECT = 4;
+
+        public Command receive(InputStream s) throws IOException {
+            StringBuffer sb = new StringBuffer();
+            top:
+            while (true) {
+                int c = s.read();
+                switch (c) {
+                    case -1:
+                        throw new IOException("Stream unexpectedly short (broken pipe)");
+                    case 0:
+                    case '\r':
+                        continue;
+                    case '\n':
+                        break top;
+                    default:
+                        sb.append((char) c);
+                }
+            }
+            if (Debug.debug) Debug.print(Debug.VERBOSE, "received: " + sb);
+            try {
+                return new Command(sb.toString());
+            } catch (Exception e) {
+                if (Debug.debug && AbstractConnection.EXCEPTION_DEBUG) Debug.print(Debug.ERR, e);
+                return new Command();
+            }
+        }
+
+        public void send(OutputStream out, int command, String... data) throws IOException {
+            StringBuffer sb = new StringBuffer();
+            switch (command) {
+                case COMMAND_AUTH:
+                    sb.append("AUTH");
+                    break;
+                case COMMAND_DATA:
+                    sb.append("DATA");
+                    break;
+                case COMMAND_REJECTED:
+                    sb.append("REJECTED");
+                    break;
+                case COMMAND_OK:
+                    sb.append("OK");
+                    break;
+                case COMMAND_BEGIN:
+                    sb.append("BEGIN");
+                    break;
+                case COMMAND_CANCEL:
+                    sb.append("CANCEL");
+                    break;
+                case COMMAND_ERROR:
+                    sb.append("ERROR");
+                    break;
+                default:
+                    return;
+            }
+            for (String s : data) {
+                sb.append(' ');
+                sb.append(s);
+            }
+            sb.append('\r');
+            sb.append('\n');
+            if (Debug.debug) Debug.print(Debug.VERBOSE, "sending: " + sb);
+            out.write(sb.toString().getBytes());
+        }
+
+        public int do_challenge(int auth, Command c) throws IOException {
+            switch (auth) {
+                case AUTH_SHA:
+                    String[] reply = stupidlyDecode(c.getData()).split(" ");
+                    if (Debug.debug) Debug.print(Debug.VERBOSE, Arrays.toString(reply));
+                    if (3 != reply.length) {
+                        if (Debug.debug) Debug.print(Debug.DEBUG, "Reply is not length 3");
+                        return ERROR;
+                    }
+                    String context = reply[0];
+                    String ID = reply[1];
+                    String serverchallenge = reply[2];
+                    MessageDigest md = null;
+                    try {
+                        md = MessageDigest.getInstance("SHA");
+                    } catch (NoSuchAlgorithmException NSAe) {
+                        if (Debug.debug && AbstractConnection.EXCEPTION_DEBUG) Debug.print(Debug.ERR, NSAe);
+                        return ERROR;
+                    }
+                    byte[] buf = new byte[8];
+                    Message.marshallintBig(System.currentTimeMillis(), buf, 0, 8);
+                    String clientchallenge = stupidlyEncode(md.digest(buf));
+                    md.reset();
+                    long start = System.currentTimeMillis();
+                    String cookie = null;
+                    while (null == cookie && (System.currentTimeMillis() - start) < LOCK_TIMEOUT)
+                        cookie = findCookie(context, ID);
+                    if (null == cookie) {
+                        if (Debug.debug)
+                            Debug.print(Debug.DEBUG, "Did not find a cookie in context " + context + " with ID " + ID);
+                        return ERROR;
+                    }
+                    String response = serverchallenge + ":" + clientchallenge + ":" + cookie;
+                    buf = md.digest(response.getBytes());
+                    if (Debug.debug)
+                        Debug.print(Debug.VERBOSE, "Response: " + response + " hash: " + Hexdump.format(buf));
+                    response = stupidlyEncode(buf);
+                    c.setResponse(stupidlyEncode(clientchallenge + " " + response));
+                    return OK;
+                default:
+                    if (Debug.debug) Debug.print(Debug.DEBUG, "Not DBUS_COOKIE_SHA1 authtype.");
+                    return ERROR;
+            }
+        }
+
+        public String challenge = "";
+        public String cookie = "";
+
+        public int do_response(int auth, String Uid, String kernelUid, Command c) {
+            MessageDigest md = null;
+            try {
+                md = MessageDigest.getInstance("SHA");
+            } catch (NoSuchAlgorithmException NSAe) {
+                if (Debug.debug && AbstractConnection.EXCEPTION_DEBUG) Debug.print(Debug.ERR, NSAe);
+                return ERROR;
+            }
+            switch (auth) {
+                case AUTH_NONE:
+                    switch (c.getMechs()) {
+                        case AUTH_ANON:
+                            return OK;
+                        case AUTH_EXTERNAL:
+                            if (0 == col.compare(Uid, c.getData()) &&
+                                    (null == kernelUid || 0 == col.compare(Uid, kernelUid)))
+                                return OK;
+                            else
+                                return ERROR;
+                        case AUTH_SHA:
+                            String context = COOKIE_CONTEXT;
+                            long id = System.currentTimeMillis();
+                            byte[] buf = new byte[8];
+                            Message.marshallintBig(id, buf, 0, 8);
+                            challenge = stupidlyEncode(md.digest(buf));
+                            Random r = new Random();
+                            r.nextBytes(buf);
+                            cookie = stupidlyEncode(md.digest(buf));
+                            try {
+                                addCookie(context, "" + id, id / 1000, cookie);
+                            } catch (IOException IOe) {
+                                if (Debug.debug && AbstractConnection.EXCEPTION_DEBUG) Debug.print(Debug.ERR, IOe);
+                            }
+                            if (Debug.debug)
+                                Debug.print(Debug.DEBUG, "Sending challenge: " + context + ' ' + id + ' ' + challenge);
+                            c.setResponse(stupidlyEncode(context + ' ' + id + ' ' + challenge));
+                            return CONTINUE;
+                        default:
+                            return ERROR;
+                    }
+                case AUTH_SHA:
+                    String[] response = stupidlyDecode(c.getData()).split(" ");
+                    if (response.length < 2) return ERROR;
+                    String cchal = response[0];
+                    String hash = response[1];
+                    String prehash = challenge + ":" + cchal + ":" + cookie;
+                    byte[] buf = md.digest(prehash.getBytes());
+                    String posthash = stupidlyEncode(buf);
+                    if (Debug.debug)
+                        Debug.print(Debug.DEBUG, "Authenticating Hash; data=" + prehash + " remote hash=" + hash + " local hash=" + posthash);
+                    if (0 == col.compare(posthash, hash))
+                        return OK;
+                    else
+                        return ERROR;
+                default:
+                    return ERROR;
+            }
+        }
+
+        public String[] getTypes(int types) {
+            switch (types) {
+                case AUTH_EXTERNAL:
+                    return new String[]{"EXTERNAL"};
+                case AUTH_SHA:
+                    return new String[]{"DBUS_COOKIE_SHA1"};
+                case AUTH_ANON:
+                    return new String[]{"ANONYMOUS"};
+                case AUTH_SHA + AUTH_EXTERNAL:
+                    return new String[]{"EXTERNAL", "DBUS_COOKIE_SHA1"};
+                case AUTH_SHA + AUTH_ANON:
+                    return new String[]{"ANONYMOUS", "DBUS_COOKIE_SHA1"};
+                case AUTH_EXTERNAL + AUTH_ANON:
+                    return new String[]{"ANONYMOUS", "EXTERNAL"};
+                case AUTH_EXTERNAL + AUTH_ANON + AUTH_SHA:
+                    return new String[]{"ANONYMOUS", "EXTERNAL", "DBUS_COOKIE_SHA1"};
+                default:
+                    return new String[]{};
+            }
+        }
+
+        /**
+         * performs SASL auth on the given streams.
+         * Mode selects whether to run as a SASL server or client.
+         * Types is a bitmask of the available auth types.
+         * Returns true if the auth was successful and false if it failed.
+         */
+        @SuppressWarnings("unchecked")
+        public boolean auth(int mode, int types, String guid, OutputStream out, InputStream in, UnixSocket us) throws IOException {
+            String username = System.getProperty("user.name");
+            String Uid = null;
+            String kernelUid = null;
+            try {
+                Class c = Class.forName("com.sun.security.auth.module.UnixSystem");
+                Method m = c.getMethod("getUid");
+                Object o = c.newInstance();
+                long uid = (Long) m.invoke(o);
+                Uid = stupidlyEncode("" + uid);
+            } catch (Exception e) {
+                Uid = stupidlyEncode(username);
+            }
+            Command c;
+            int failed = 0;
+            int current = 0;
+            int state = INITIAL_STATE;
+
+            while (state != AUTHENTICATED && state != FAILED) {
+                if (Debug.debug) Debug.print(Debug.VERBOSE, "AUTH state: " + state);
+                switch (mode) {
+                    case MODE_CLIENT:
+                        switch (state) {
+                            case INITIAL_STATE:
+                                if (null == us)
+                                    out.write(new byte[]{0});
+                                else
+                                    us.sendCredentialByte((byte) 0);
+                                send(out, COMMAND_AUTH);
+                                state = WAIT_DATA;
+                                break;
+                            case WAIT_DATA:
+                                c = receive(in);
+                                switch (c.getCommand()) {
+                                    case COMMAND_DATA:
+                                        switch (do_challenge(current, c)) {
+                                            case CONTINUE:
+                                                send(out, COMMAND_DATA, c.getResponse());
+                                                break;
+                                            case OK:
+                                                send(out, COMMAND_DATA, c.getResponse());
+                                                state = WAIT_OK;
+                                                break;
+                                            case ERROR:
+                                                send(out, COMMAND_ERROR, c.getResponse());
+                                                break;
+                                        }
+                                        break;
+                                    case COMMAND_REJECTED:
+                                        failed |= current;
+                                        int available = c.getMechs() & (~failed);
+                                        if (0 != (available & AUTH_EXTERNAL)) {
+                                            send(out, COMMAND_AUTH, "EXTERNAL", Uid);
+                                            current = AUTH_EXTERNAL;
+                                        } else if (0 != (available & AUTH_SHA)) {
+                                            send(out, COMMAND_AUTH, "DBUS_COOKIE_SHA1", Uid);
+                                            current = AUTH_SHA;
+                                        } else if (0 != (available & AUTH_ANON)) {
+                                            send(out, COMMAND_AUTH, "ANONYMOUS");
+                                            current = AUTH_ANON;
+                                        } else state = FAILED;
+                                        break;
+                                    case COMMAND_ERROR:
+                                        send(out, COMMAND_CANCEL);
+                                        state = WAIT_REJECT;
+                                        break;
+                                    case COMMAND_OK:
+                                        send(out, COMMAND_BEGIN);
+                                        state = AUTHENTICATED;
+                                        break;
+                                    default:
+                                        send(out, COMMAND_ERROR, "Got invalid command");
+                                        break;
+                                }
+                                break;
+                            case WAIT_OK:
+                                c = receive(in);
+                                switch (c.getCommand()) {
+                                    case COMMAND_OK:
+                                        send(out, COMMAND_BEGIN);
+                                        state = AUTHENTICATED;
+                                        break;
+                                    case COMMAND_ERROR:
+                                    case COMMAND_DATA:
+                                        send(out, COMMAND_CANCEL);
+                                        state = WAIT_REJECT;
+                                        break;
+                                    case COMMAND_REJECTED:
+                                        failed |= current;
+                                        int available = c.getMechs() & (~failed);
+                                        state = WAIT_DATA;
+                                        if (0 != (available & AUTH_EXTERNAL)) {
+                                            send(out, COMMAND_AUTH, "EXTERNAL", Uid);
+                                            current = AUTH_EXTERNAL;
+                                        } else if (0 != (available & AUTH_SHA)) {
+                                            send(out, COMMAND_AUTH, "DBUS_COOKIE_SHA1", Uid);
+                                            current = AUTH_SHA;
+                                        } else if (0 != (available & AUTH_ANON)) {
+                                            send(out, COMMAND_AUTH, "ANONYMOUS");
+                                            current = AUTH_ANON;
+                                        } else state = FAILED;
+                                        break;
+                                    default:
+                                        send(out, COMMAND_ERROR, "Got invalid command");
+                                        break;
+                                }
+                                break;
+                            case WAIT_REJECT:
+                                c = receive(in);
+                                switch (c.getCommand()) {
+                                    case COMMAND_REJECTED:
+                                        failed |= current;
+                                        int available = c.getMechs() & (~failed);
+                                        if (0 != (available & AUTH_EXTERNAL)) {
+                                            send(out, COMMAND_AUTH, "EXTERNAL", Uid);
+                                            current = AUTH_EXTERNAL;
+                                        } else if (0 != (available & AUTH_SHA)) {
+                                            send(out, COMMAND_AUTH, "DBUS_COOKIE_SHA1", Uid);
+                                            current = AUTH_SHA;
+                                        } else if (0 != (available & AUTH_ANON)) {
+                                            send(out, COMMAND_AUTH, "ANONYMOUS");
+                                            current = AUTH_ANON;
+                                        } else state = FAILED;
+                                        break;
+                                    default:
+                                        state = FAILED;
+                                        break;
+                                }
+                                break;
+                            default:
+                                state = FAILED;
+                        }
+                        break;
+                    case MODE_SERVER:
+                        switch (state) {
+                            case INITIAL_STATE:
+                                byte[] buf = new byte[1];
+                                if (null == us) {
+                                    in.read(buf);
+                                } else {
+                                    buf[0] = us.recvCredentialByte();
+                                    int kuid = us.getPeerUID();
+                                    if (kuid >= 0)
+                                        kernelUid = stupidlyEncode("" + kuid);
+                                }
+                                if (0 != buf[0]) state = FAILED;
+                                else state = WAIT_AUTH;
+                                break;
+                            case WAIT_AUTH:
+                                c = receive(in);
+                                switch (c.getCommand()) {
+                                    case COMMAND_AUTH:
+                                        if (null == c.getData()) {
+                                            send(out, COMMAND_REJECTED, getTypes(types));
+                                        } else {
+                                            switch (do_response(current, Uid, kernelUid, c)) {
+                                                case CONTINUE:
+                                                    send(out, COMMAND_DATA, c.getResponse());
+                                                    current = c.getMechs();
+                                                    state = WAIT_DATA;
+                                                    break;
+                                                case OK:
+                                                    send(out, COMMAND_OK, guid);
+                                                    state = WAIT_BEGIN;
+                                                    current = 0;
+                                                    break;
+                                                case REJECT:
+                                                    send(out, COMMAND_REJECTED, getTypes(types));
+                                                    current = 0;
+                                                    break;
+                                            }
+                                        }
+                                        break;
+                                    case COMMAND_ERROR:
+                                        send(out, COMMAND_REJECTED, getTypes(types));
+                                        break;
+                                    case COMMAND_BEGIN:
+                                        state = FAILED;
+                                        break;
+                                    default:
+                                        send(out, COMMAND_ERROR, "Got invalid command");
+                                        break;
+                                }
+                                break;
+                            case WAIT_DATA:
+                                c = receive(in);
+                                switch (c.getCommand()) {
+                                    case COMMAND_DATA:
+                                        switch (do_response(current, Uid, kernelUid, c)) {
+                                            case CONTINUE:
+                                                send(out, COMMAND_DATA, c.getResponse());
+                                                state = WAIT_DATA;
+                                                break;
+                                            case OK:
+                                                send(out, COMMAND_OK, guid);
+                                                state = WAIT_BEGIN;
+                                                current = 0;
+                                                break;
+                                            case REJECT:
+                                                send(out, COMMAND_REJECTED, getTypes(types));
+                                                current = 0;
+                                                break;
+                                        }
+                                        break;
+                                    case COMMAND_ERROR:
+                                    case COMMAND_CANCEL:
+                                        send(out, COMMAND_REJECTED, getTypes(types));
+                                        state = WAIT_AUTH;
+                                        break;
+                                    case COMMAND_BEGIN:
+                                        state = FAILED;
+                                        break;
+                                    default:
+                                        send(out, COMMAND_ERROR, "Got invalid command");
+                                        break;
+                                }
+                                break;
+                            case WAIT_BEGIN:
+                                c = receive(in);
+                                switch (c.getCommand()) {
+                                    case COMMAND_ERROR:
+                                    case COMMAND_CANCEL:
+                                        send(out, COMMAND_REJECTED, getTypes(types));
+                                        state = WAIT_AUTH;
+                                        break;
+                                    case COMMAND_BEGIN:
+                                        state = AUTHENTICATED;
+                                        break;
+                                    default:
+                                        send(out, COMMAND_ERROR, "Got invalid command");
+                                        break;
+                                }
+                                break;
+                            default:
+                                state = FAILED;
+                        }
+                        break;
+                    default:
+                        return false;
+                }
+            }
+
+            return state == AUTHENTICATED;
+        }
+    }
+
+    public MessageReader min;
+    public MessageWriter mout;
+
+    public Transport() {
+    }
+
+    public static String genGUID() {
+        Random r = new Random();
+        byte[] buf = new byte[16];
+        r.nextBytes(buf);
+        String guid = Hexdump.toHex(buf);
+        return guid.replaceAll(" ", "");
+    }
+
+    public Transport(BusAddress address) throws IOException {
+        connect(address);
+    }
+
+    public Transport(String address) throws IOException, ParseException {
+        connect(new BusAddress(address));
+    }
+
+    public Transport(String address, int timeout) throws IOException, ParseException {
+        connect(new BusAddress(address), timeout);
+    }
+
+    public void connect(String address) throws IOException, ParseException {
+        connect(new BusAddress(address), 0);
+    }
+
+    public void connect(String address, int timeout) throws IOException, ParseException {
+        connect(new BusAddress(address), timeout);
+    }
+
+    public void connect(BusAddress address) throws IOException {
+        connect(address, 0);
+    }
+
+    public void connect(BusAddress address, int timeout) throws IOException {
+        if (Debug.debug) Debug.print(Debug.INFO, "Connecting to " + address);
+        OutputStream out = null;
+        InputStream in = null;
+        UnixSocket us = null;
+        Socket s = null;
+        int mode = 0;
+        int types = 0;
+        if ("unix".equals(address.getType())) {
+            types = SASL.AUTH_EXTERNAL;
+            mode = SASL.MODE_CLIENT;
+            us = new UnixSocket();
+            if (null != address.getParameter("abstract"))
+                us.connect(new UnixSocketAddress(address.getParameter("abstract"), true));
+            else if (null != address.getParameter("path"))
+                us.connect(new UnixSocketAddress(address.getParameter("path"), false));
+            us.setPassCred(true);
+            in = us.getInputStream();
+            out = us.getOutputStream();
+        } else if ("tcp".equals(address.getType())) {
+            types = SASL.AUTH_SHA;
+            if (null != address.getParameter("listen")) {
+                mode = SASL.MODE_SERVER;
+                ServerSocket ss = new ServerSocket();
+                ss.bind(new InetSocketAddress(address.getParameter("host"), Integer.parseInt(address.getParameter("port"))));
+                s = ss.accept();
+            } else {
+                mode = SASL.MODE_CLIENT;
+                s = new Socket();
+                s.connect(new InetSocketAddress(address.getParameter("host"), Integer.parseInt(address.getParameter("port"))));
+            }
+            in = s.getInputStream();
+            out = s.getOutputStream();
+        } else {
+            throw new IOException(getString("unknownAddress") + address.getType());
+        }
+
+        if (!(new SASL()).auth(mode, types, address.getParameter("guid"), out, in, us)) {
+            out.close();
+            throw new IOException(getString("errorAuth"));
+        }
+        if (null != us) {
+            if (Debug.debug) Debug.print(Debug.VERBOSE, "Setting timeout to " + timeout + " on Socket");
+            if (timeout == 1)
+                us.setBlocking(false);
+            else
+                us.setSoTimeout(timeout);
+        }
+        if (null != s) {
+            if (Debug.debug) Debug.print(Debug.VERBOSE, "Setting timeout to " + timeout + " on Socket");
+            s.setSoTimeout(timeout);
+        }
+        mout = new MessageWriter(out);
+        min = new MessageReader(in);
+    }
+
+    public void disconnect() throws IOException {
+        if (Debug.debug) Debug.print(Debug.INFO, "Disconnecting Transport");
+        min.close();
+        mout.close();
+    }
+}
+
+
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/Tuple.java b/federation/sssd/src/main/java/org/freedesktop/dbus/Tuple.java
new file mode 100644
index 0000000..5fc13d5
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/Tuple.java
@@ -0,0 +1,24 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+/**
+ * This class should be extended to create Tuples.
+ * Any such class may be used as the return type for a method
+ * which returns multiple values.
+ * All fields in the Tuple which you wish to be serialized and sent to the
+ * remote method should be annotated with the org.freedesktop.dbus.Position
+ * annotation, in the order they should appear to DBus.
+ */
+public abstract class Tuple extends Container {
+    public Tuple() {
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/types/DBusListType.java b/federation/sssd/src/main/java/org/freedesktop/dbus/types/DBusListType.java
new file mode 100644
index 0000000..a00c307
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/types/DBusListType.java
@@ -0,0 +1,44 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus.types;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.List;
+
+/**
+ * The type of a list.
+ * Should be used whenever you need a Type variable for a list.
+ */
+public class DBusListType implements ParameterizedType {
+    private Type v;
+
+    /**
+     * Create a List type.
+     *
+     * @param v Type of the list contents.
+     */
+    public DBusListType(Type v) {
+        this.v = v;
+    }
+
+    public Type[] getActualTypeArguments() {
+        return new Type[]{v};
+    }
+
+    public Type getRawType() {
+        return List.class;
+    }
+
+    public Type getOwnerType() {
+        return null;
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/types/DBusMapType.java b/federation/sssd/src/main/java/org/freedesktop/dbus/types/DBusMapType.java
new file mode 100644
index 0000000..754e0a2
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/types/DBusMapType.java
@@ -0,0 +1,47 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus.types;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.Map;
+
+/**
+ * The type of a map.
+ * Should be used whenever you need a Type variable for a map.
+ */
+public class DBusMapType implements ParameterizedType {
+    private Type k;
+    private Type v;
+
+    /**
+     * Create a map type.
+     *
+     * @param k The type of the keys.
+     * @param v The type of the values.
+     */
+    public DBusMapType(Type k, Type v) {
+        this.k = k;
+        this.v = v;
+    }
+
+    public Type[] getActualTypeArguments() {
+        return new Type[]{k, v};
+    }
+
+    public Type getRawType() {
+        return Map.class;
+    }
+
+    public Type getOwnerType() {
+        return null;
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/types/DBusStructType.java b/federation/sssd/src/main/java/org/freedesktop/dbus/types/DBusStructType.java
new file mode 100644
index 0000000..fda2065
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/types/DBusStructType.java
@@ -0,0 +1,45 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus.types;
+
+import org.freedesktop.dbus.Struct;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+
+/**
+ * The type of a struct.
+ * Should be used whenever you need a Type variable for a struct.
+ */
+public class DBusStructType implements ParameterizedType {
+    private Type[] contents;
+
+    /**
+     * Create a struct type.
+     *
+     * @param contents The types contained in this struct.
+     */
+    public DBusStructType(Type... contents) {
+        this.contents = contents;
+    }
+
+    public Type[] getActualTypeArguments() {
+        return contents;
+    }
+
+    public Type getRawType() {
+        return Struct.class;
+    }
+
+    public Type getOwnerType() {
+        return null;
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/TypeSignature.java b/federation/sssd/src/main/java/org/freedesktop/dbus/TypeSignature.java
new file mode 100644
index 0000000..eaad166
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/TypeSignature.java
@@ -0,0 +1,37 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.dbus.exceptions.DBusException;
+
+import java.lang.reflect.Type;
+
+public class TypeSignature {
+    String sig;
+
+    public TypeSignature(String sig) {
+        this.sig = sig;
+    }
+
+    public TypeSignature(Type[] types) throws DBusException {
+        StringBuffer sb = new StringBuffer();
+        for (Type t : types) {
+            String[] ts = Marshalling.getDBusType(t);
+            for (String s : ts)
+                sb.append(s);
+        }
+        this.sig = sb.toString();
+    }
+
+    public String getSig() {
+        return sig;
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/UInt16.java b/federation/sssd/src/main/java/org/freedesktop/dbus/UInt16.java
new file mode 100644
index 0000000..a8f0600
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/UInt16.java
@@ -0,0 +1,122 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import java.text.MessageFormat;
+
+import static org.freedesktop.dbus.Gettext.getString;
+
+/**
+ * Class to represent 16-bit unsigned integers.
+ */
+@SuppressWarnings("serial")
+public class UInt16 extends Number implements Comparable<UInt16> {
+    /**
+     * Maximum possible value.
+     */
+    public static final int MAX_VALUE = 65535;
+    /**
+     * Minimum possible value.
+     */
+    public static final int MIN_VALUE = 0;
+    private int value;
+
+    /**
+     * Create a UInt16 from an int.
+     *
+     * @param value Must be within MIN_VALUE–MAX_VALUE
+     * @throws NumberFormatException if value is not between MIN_VALUE and MAX_VALUE
+     */
+    public UInt16(int value) {
+        if (value < MIN_VALUE || value > MAX_VALUE)
+            throw new NumberFormatException(MessageFormat.format(getString("isNotBetween"), new Object[]{value, MIN_VALUE, MAX_VALUE}));
+        this.value = value;
+    }
+
+    /**
+     * Create a UInt16 from a String.
+     *
+     * @param value Must parse to a valid integer within MIN_VALUE–MAX_VALUE
+     * @throws NumberFormatException if value is not an integer between MIN_VALUE and MAX_VALUE
+     */
+    public UInt16(String value) {
+        this(Integer.parseInt(value));
+    }
+
+    /**
+     * The value of this as a byte.
+     */
+    public byte byteValue() {
+        return (byte) value;
+    }
+
+    /**
+     * The value of this as a double.
+     */
+    public double doubleValue() {
+        return (double) value;
+    }
+
+    /**
+     * The value of this as a float.
+     */
+    public float floatValue() {
+        return (float) value;
+    }
+
+    /**
+     * The value of this as a int.
+     */
+    public int intValue() {
+        return /*(int)*/ value;
+    }
+
+    /**
+     * The value of this as a long.
+     */
+    public long longValue() {
+        return (long) value;
+    }
+
+    /**
+     * The value of this as a short.
+     */
+    public short shortValue() {
+        return (short) value;
+    }
+
+    /**
+     * Test two UInt16s for equality.
+     */
+    public boolean equals(Object o) {
+        return o instanceof UInt16 && ((UInt16) o).value == this.value;
+    }
+
+    public int hashCode() {
+        return /*(int)*/ value;
+    }
+
+    /**
+     * Compare two UInt16s.
+     *
+     * @return 0 if equal, -ve or +ve if they are different.
+     */
+    public int compareTo(UInt16 other) {
+        return /*(int)*/ (this.value - other.value);
+    }
+
+    /**
+     * The value of this as a string.
+     */
+    public String toString() {
+        return "" + value;
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/UInt32.java b/federation/sssd/src/main/java/org/freedesktop/dbus/UInt32.java
new file mode 100644
index 0000000..4651919
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/UInt32.java
@@ -0,0 +1,122 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import java.text.MessageFormat;
+
+import static org.freedesktop.dbus.Gettext.getString;
+
+/**
+ * Class to represent unsigned 32-bit numbers.
+ */
+@SuppressWarnings("serial")
+public class UInt32 extends Number implements Comparable<UInt32> {
+    /**
+     * Maximum allowed value
+     */
+    public static final long MAX_VALUE = 4294967295L;
+    /**
+     * Minimum allowed value
+     */
+    public static final long MIN_VALUE = 0;
+    private long value;
+
+    /**
+     * Create a UInt32 from a long.
+     *
+     * @param value Must be a valid integer within MIN_VALUE–MAX_VALUE
+     * @throws NumberFormatException if value is not between MIN_VALUE and MAX_VALUE
+     */
+    public UInt32(long value) {
+        if (value < MIN_VALUE || value > MAX_VALUE)
+            throw new NumberFormatException(MessageFormat.format(getString("isNotBetween"), new Object[]{value, MIN_VALUE, MAX_VALUE}));
+        this.value = value;
+    }
+
+    /**
+     * Create a UInt32 from a String.
+     *
+     * @param value Must parse to a valid integer within MIN_VALUE–MAX_VALUE
+     * @throws NumberFormatException if value is not an integer between MIN_VALUE and MAX_VALUE
+     */
+    public UInt32(String value) {
+        this(Long.parseLong(value));
+    }
+
+    /**
+     * The value of this as a byte.
+     */
+    public byte byteValue() {
+        return (byte) value;
+    }
+
+    /**
+     * The value of this as a double.
+     */
+    public double doubleValue() {
+        return (double) value;
+    }
+
+    /**
+     * The value of this as a float.
+     */
+    public float floatValue() {
+        return (float) value;
+    }
+
+    /**
+     * The value of this as a int.
+     */
+    public int intValue() {
+        return (int) value;
+    }
+
+    /**
+     * The value of this as a long.
+     */
+    public long longValue() {
+        return /*(long)*/ value;
+    }
+
+    /**
+     * The value of this as a short.
+     */
+    public short shortValue() {
+        return (short) value;
+    }
+
+    /**
+     * Test two UInt32s for equality.
+     */
+    public boolean equals(Object o) {
+        return o instanceof UInt32 && ((UInt32) o).value == this.value;
+    }
+
+    public int hashCode() {
+        return (int) value;
+    }
+
+    /**
+     * Compare two UInt32s.
+     *
+     * @return 0 if equal, -ve or +ve if they are different.
+     */
+    public int compareTo(UInt32 other) {
+        return (int) (this.value - other.value);
+    }
+
+    /**
+     * The value of this as a string
+     */
+    public String toString() {
+        return "" + value;
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/UInt64.java b/federation/sssd/src/main/java/org/freedesktop/dbus/UInt64.java
new file mode 100644
index 0000000..fde2cf0
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/UInt64.java
@@ -0,0 +1,203 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import java.math.BigInteger;
+import java.text.MessageFormat;
+
+import static org.freedesktop.dbus.Gettext.getString;
+
+/**
+ * Class to represent unsigned 64-bit numbers.
+ * Warning: Any functions which take or return a <tt>long</tt>
+ * are restricted to the range of a signed 64bit number.
+ * Use the BigInteger methods if you wish access to the full
+ * range.
+ */
+@SuppressWarnings("serial")
+public class UInt64 extends Number implements Comparable<UInt64> {
+    /**
+     * Maximum allowed value (when accessed as a long)
+     */
+    public static final long MAX_LONG_VALUE = Long.MAX_VALUE;
+    /**
+     * Maximum allowed value (when accessed as a BigInteger)
+     */
+    public static final BigInteger MAX_BIG_VALUE = new BigInteger("18446744073709551615");
+    /**
+     * Minimum allowed value
+     */
+    public static final long MIN_VALUE = 0;
+    private BigInteger value;
+    private long top;
+    private long bottom;
+
+    /**
+     * Create a UInt64 from a long.
+     *
+     * @param value Must be a valid integer within MIN_VALUE–MAX_VALUE
+     * @throws NumberFormatException if value is not between MIN_VALUE and MAX_VALUE
+     */
+    public UInt64(long value) {
+        if (value < MIN_VALUE || value > MAX_LONG_VALUE)
+            throw new NumberFormatException(MessageFormat.format(getString("isNotBetween"), new Object[]{value, MIN_VALUE, MAX_LONG_VALUE}));
+        this.value = new BigInteger("" + value);
+        this.top = this.value.shiftRight(32).and(new BigInteger("4294967295")).longValue();
+        this.bottom = this.value.and(new BigInteger("4294967295")).longValue();
+    }
+
+    /**
+     * Create a UInt64 from two longs.
+     *
+     * @param top    Most significant 4 bytes.
+     * @param bottom Least significant 4 bytes.
+     */
+    public UInt64(long top, long bottom) {
+        BigInteger a = new BigInteger("" + top);
+        a = a.shiftLeft(32);
+        a = a.add(new BigInteger("" + bottom));
+        if (0 > a.compareTo(BigInteger.ZERO))
+            throw new NumberFormatException(MessageFormat.format(getString("isNotBetween"), new Object[]{a, MIN_VALUE, MAX_BIG_VALUE}));
+        if (0 < a.compareTo(MAX_BIG_VALUE))
+            throw new NumberFormatException(MessageFormat.format(getString("isNotBetween"), new Object[]{a, MIN_VALUE, MAX_BIG_VALUE}));
+        this.value = a;
+        this.top = top;
+        this.bottom = bottom;
+    }
+
+    /**
+     * Create a UInt64 from a BigInteger
+     *
+     * @param value Must be a valid BigInteger between MIN_VALUE–MAX_BIG_VALUE
+     * @throws NumberFormatException if value is not an integer between MIN_VALUE and MAX_BIG_VALUE
+     */
+    public UInt64(BigInteger value) {
+        if (null == value)
+            throw new NumberFormatException(MessageFormat.format(getString("isNotBetween"), new Object[]{value, MIN_VALUE, MAX_BIG_VALUE}));
+        if (0 > value.compareTo(BigInteger.ZERO))
+            throw new NumberFormatException(MessageFormat.format(getString("isNotBetween"), new Object[]{value, MIN_VALUE, MAX_BIG_VALUE}));
+        if (0 < value.compareTo(MAX_BIG_VALUE))
+            throw new NumberFormatException(MessageFormat.format(getString("isNotBetween"), new Object[]{value, MIN_VALUE, MAX_BIG_VALUE}));
+        this.value = value;
+        this.top = this.value.shiftRight(32).and(new BigInteger("4294967295")).longValue();
+        this.bottom = this.value.and(new BigInteger("4294967295")).longValue();
+    }
+
+    /**
+     * Create a UInt64 from a String.
+     *
+     * @param value Must parse to a valid integer within MIN_VALUE–MAX_BIG_VALUE
+     * @throws NumberFormatException if value is not an integer between MIN_VALUE and MAX_BIG_VALUE
+     */
+    public UInt64(String value) {
+        if (null == value)
+            throw new NumberFormatException(MessageFormat.format(getString("isNotBetween"), new Object[]{value, MIN_VALUE, MAX_BIG_VALUE}));
+        BigInteger a = new BigInteger(value);
+        if (0 > a.compareTo(BigInteger.ZERO))
+            throw new NumberFormatException(MessageFormat.format(getString("isNotBetween"), new Object[]{value, MIN_VALUE, MAX_BIG_VALUE}));
+        if (0 < a.compareTo(MAX_BIG_VALUE))
+            throw new NumberFormatException(MessageFormat.format(getString("isNotBetween"), new Object[]{value, MIN_VALUE, MAX_BIG_VALUE}));
+        this.value = a;
+        this.top = this.value.shiftRight(32).and(new BigInteger("4294967295")).longValue();
+        this.bottom = this.value.and(new BigInteger("4294967295")).longValue();
+    }
+
+    /**
+     * The value of this as a BigInteger.
+     */
+    public BigInteger value() {
+        return value;
+    }
+
+    /**
+     * The value of this as a byte.
+     */
+    public byte byteValue() {
+        return value.byteValue();
+    }
+
+    /**
+     * The value of this as a double.
+     */
+    public double doubleValue() {
+        return value.doubleValue();
+    }
+
+    /**
+     * The value of this as a float.
+     */
+    public float floatValue() {
+        return value.floatValue();
+    }
+
+    /**
+     * The value of this as a int.
+     */
+    public int intValue() {
+        return value.intValue();
+    }
+
+    /**
+     * The value of this as a long.
+     */
+    public long longValue() {
+        return value.longValue();
+    }
+
+    /**
+     * The value of this as a short.
+     */
+    public short shortValue() {
+        return value.shortValue();
+    }
+
+    /**
+     * Test two UInt64s for equality.
+     */
+    public boolean equals(Object o) {
+        return o instanceof UInt64 && this.value.equals(((UInt64) o).value);
+    }
+
+    public int hashCode() {
+        return value.hashCode();
+    }
+
+    /**
+     * Compare two UInt32s.
+     *
+     * @return 0 if equal, -ve or +ve if they are different.
+     */
+    public int compareTo(UInt64 other) {
+        return this.value.compareTo(other.value);
+    }
+
+    /**
+     * The value of this as a string.
+     */
+    public String toString() {
+        return value.toString();
+    }
+
+    /**
+     * Most significant 4 bytes.
+     */
+    public long top() {
+        return top;
+    }
+
+    /**
+     * Least significant 4 bytes.
+     */
+    public long bottom() {
+        return bottom;
+    }
+}
+
                diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/Variant.java b/federation/sssd/src/main/java/org/freedesktop/dbus/Variant.java
new file mode 100644
index 0000000..8fe21a5
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/Variant.java
@@ -0,0 +1,136 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import cx.ath.matthew.debug.Debug;
+import org.freedesktop.dbus.exceptions.DBusException;
+
+import java.lang.reflect.Type;
+import java.text.MessageFormat;
+import java.util.Vector;
+
+import static org.freedesktop.dbus.Gettext.getString;
+
+/**
+ * A Wrapper class for Variant values.
+ * A method on DBus can send or receive a Variant.
+ * This will wrap another value whose type is determined at runtime.
+ * The Variant may be parameterized to restrict the types it may accept.
+ */
+public class Variant<T> {
+    private final T o;
+    private final Type type;
+    private final String sig;
+
+    /**
+     * Create a Variant from a basic type object.
+     *
+     * @param o The wrapped value.
+     * @throws IllegalArugmentException If you try and wrap Null or an object of a non-basic type.
+     */
+    public Variant(T o) throws IllegalArgumentException {
+        if (null == o) throw new IllegalArgumentException(getString("cannotWrapNullInVariant"));
+        type = o.getClass();
+        try {
+            String[] ss = Marshalling.getDBusType(o.getClass(), true);
+            if (ss.length != 1)
+                throw new IllegalArgumentException(getString("cannotWrapMultiValuedInVariant") + type);
+            this.sig = ss[0];
+        } catch (DBusException DBe) {
+            if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBe);
+            throw new IllegalArgumentException(MessageFormat.format(getString("cannotWrapUnqualifiedVariant"), new Object[]{o.getClass(), DBe.getMessage()}));
+        }
+        this.o = o;
+    }
+
+    /**
+     * Create a Variant.
+     *
+     * @param o    The wrapped value.
+     * @param type The explicit type of the value.
+     * @throws IllegalArugmentException If you try and wrap Null or an object which cannot be sent over DBus.
+     */
+    public Variant(T o, Type type) throws IllegalArgumentException {
+        if (null == o) throw new IllegalArgumentException(getString("cannotWrapNullInVariant"));
+        this.type = type;
+        try {
+            String[] ss = Marshalling.getDBusType(type);
+            if (ss.length != 1)
+                throw new IllegalArgumentException(getString("cannotWrapMultiValuedInVariant") + type);
+            this.sig = ss[0];
+        } catch (DBusException DBe) {
+            if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBe);
+            throw new IllegalArgumentException(MessageFormat.format(getString("cannotWrapUnqualifiedVariant"), new Object[]{type, DBe.getMessage()}));
+        }
+        this.o = o;
+    }
+
+    /**
+     * Create a Variant.
+     *
+     * @param o   The wrapped value.
+     * @param sig The explicit type of the value, as a dbus type string.
+     * @throws IllegalArugmentException If you try and wrap Null or an object which cannot be sent over DBus.
+     */
+    public Variant(T o, String sig) throws IllegalArgumentException {
+        if (null == o) throw new IllegalArgumentException(getString("cannotWrapNullInVariant"));
+        this.sig = sig;
+        try {
+            Vector<Type> ts = new Vector<Type>();
+            Marshalling.getJavaType(sig, ts, 1);
+            if (ts.size() != 1)
+                throw new IllegalArgumentException(getString("cannotWrapNoTypesInVariant") + sig);
+            this.type = ts.get(0);
+        } catch (DBusException DBe) {
+            if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBe);
+            throw new IllegalArgumentException(MessageFormat.format(getString("cannotWrapUnqualifiedVariant"), new Object[]{sig, DBe.getMessage()}));
+        }
+        this.o = o;
+    }
+
+    /**
+     * Return the wrapped value.
+     */
+    public T getValue() {
+        return o;
+    }
+
+    /**
+     * Return the type of the wrapped value.
+     */
+    public Type getType() {
+        return type;
+    }
+
+    /**
+     * Return the dbus signature of the wrapped value.
+     */
+    public String getSig() {
+        return sig;
+    }
+
+    /**
+     * Format the Variant as a string.
+     */
+    public String toString() {
+        return "[" + o + "]";
+    }
+
+    /**
+     * Compare this Variant with another by comparing contents
+     */
+    @SuppressWarnings("unchecked")
+    public boolean equals(Object other) {
+        if (null == other) return false;
+        if (!(other instanceof Variant)) return false;
+        return this.o.equals(((Variant<? extends Object>) other).o);
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/sssd/infopipe/Cache.java b/federation/sssd/src/main/java/org/freedesktop/sssd/infopipe/Cache.java
new file mode 100644
index 0000000..1a45839
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/sssd/infopipe/Cache.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.freedesktop.sssd.infopipe;
+
+import org.freedesktop.dbus.DBusInterface;
+
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bruno@abstractj.org">Bruno Oliveira</a>.
+ */
+public interface Cache extends DBusInterface {
+
+    List<DBusInterface> List();
+
+    List<DBusInterface> ListByDomain(String domain_name);
+
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/sssd/infopipe/InfoPipe.java b/federation/sssd/src/main/java/org/freedesktop/sssd/infopipe/InfoPipe.java
new file mode 100644
index 0000000..8791170
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/sssd/infopipe/InfoPipe.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.freedesktop.sssd.infopipe;
+
+import org.freedesktop.dbus.DBusInterface;
+import org.freedesktop.dbus.DBusInterfaceName;
+import org.freedesktop.dbus.DBusMemberName;
+import org.freedesktop.dbus.Variant;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:bruno@abstractj.org">Bruno Oliveira</a>.
+ */
+@DBusInterfaceName("org.freedesktop.sssd.infopipe")
+public interface InfoPipe extends DBusInterface {
+
+    String OBJECTPATH = "/org/freedesktop/sssd/infopipe";
+
+    @DBusMemberName("GetUserAttr")
+    Map<String, Variant> getUserAttributes(String user, List<String> attr);
+
+    @DBusMemberName("GetUserGroups")
+    List<String> getUserGroups(String user);
+
+}
                diff --git a/federation/sssd/src/main/java/org/freedesktop/sssd/infopipe/User.java b/federation/sssd/src/main/java/org/freedesktop/sssd/infopipe/User.java
new file mode 100644
index 0000000..896b80a
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/sssd/infopipe/User.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.freedesktop.sssd.infopipe;
+
+import org.freedesktop.dbus.DBusInterface;
+import org.freedesktop.dbus.DBusInterfaceName;
+import org.freedesktop.dbus.DBusMemberName;
+
+/**
+ * @author <a href="mailto:bruno@abstractj.org">Bruno Oliveira</a>.
+ */
+@DBusInterfaceName("org.freedesktop.sssd.infopipe.Users")
+public interface User extends DBusInterface {
+
+    String OBJECTPATH = "/org/freedesktop/sssd/infopipe/Users";
+
+    @DBusMemberName("FindByCertificate")
+    DBusInterface findByCertificate(String pem_cert);
+
+}
                diff --git a/federation/sssd/src/main/java/org/jvnet/libpam/impl/BSDCLibrary.java b/federation/sssd/src/main/java/org/jvnet/libpam/impl/BSDCLibrary.java
new file mode 100644
index 0000000..0de8a2a
--- /dev/null
+++ b/federation/sssd/src/main/java/org/jvnet/libpam/impl/BSDCLibrary.java
@@ -0,0 +1,34 @@
+/*
+ *  The MIT License
+ * 
+ *  Copyright 2011, Sun Microsystems, Inc.
+ * 
+ *  Permission is hereby granted, free of charge, to any person obtaining a copy
+ *  of this software and associated documentation files (the "Software"), to deal
+ *  in the Software without restriction, including without limitation the rights
+ *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ *  copies of the Software, and to permit persons to whom the Software is
+ *  furnished to do so, subject to the following conditions:
+ * 
+ *  The above copyright notice and this permission notice shall be included in
+ *  all copies or substantial portions of the Software.
+ * 
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ *  THE SOFTWARE.
+ */
+
+package org.jvnet.libpam.impl;
+
+/**
+ * @author Sebastian Sdorra
+ */
+public interface BSDCLibrary extends CLibrary {
+
+    BSDPasswd getpwnam(String username);
+
+}
                diff --git a/federation/sssd/src/main/java/org/jvnet/libpam/impl/BSDPasswd.java b/federation/sssd/src/main/java/org/jvnet/libpam/impl/BSDPasswd.java
new file mode 100644
index 0000000..2e437bb
--- /dev/null
+++ b/federation/sssd/src/main/java/org/jvnet/libpam/impl/BSDPasswd.java
@@ -0,0 +1,93 @@
+/*
+ *  The MIT License
+ *
+ *  Copyright 2011, Sun Microsystems, Inc.
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a copy
+ *  of this software and associated documentation files (the "Software"), to deal
+ *  in the Software without restriction, including without limitation the rights
+ *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ *  copies of the Software, and to permit persons to whom the Software is
+ *  furnished to do so, subject to the following conditions:
+ *
+ *  The above copyright notice and this permission notice shall be included in
+ *  all copies or substantial portions of the Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ *  THE SOFTWARE.
+ */
+
+package org.jvnet.libpam.impl;
+
+import org.jvnet.libpam.impl.CLibrary.passwd;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * FreeeBSD, OpenBSD and MacOS passwd
+ * <p>
+ * struct passwd {
+ * char    *pw_name;
+ * char    *pw_passwd;
+ * uid_t   pw_uid;
+ * gid_t   pw_gid;
+ * time_t pw_change;
+ * char    *pw_class;
+ * char    *pw_gecos;
+ * char    *pw_dir;
+ * char    *pw_shell;
+ * time_t pw_expire;
+ * };
+ *
+ * @author Sebastian Sdorra
+ */
+public class BSDPasswd extends passwd {
+    /* password change time */
+    public long pw_change;
+
+    /* user access class */
+    public String pw_class;
+
+    /* Honeywell login info */
+    public String pw_gecos;
+
+    /* home directory */
+    public String pw_dir;
+
+    /* default shell */
+    public String pw_shell;
+
+    /* account expiration */
+    public long pw_expire;
+
+    @Override
+    public String getPwGecos() {
+        return pw_gecos;
+    }
+
+    @Override
+    public String getPwDir() {
+        return pw_dir;
+    }
+
+    @Override
+    public String getPwShell() {
+        return pw_shell;
+    }
+
+    @Override
+    protected List getFieldOrder() {
+        List fieldOrder = new ArrayList(super.getFieldOrder());
+        fieldOrder.addAll(Arrays.asList("pw_change", "pw_class", "pw_gecos",
+                "pw_dir", "pw_shell", "pw_expire"));
+        return fieldOrder;
+    }
+
+}
                diff --git a/federation/sssd/src/main/java/org/jvnet/libpam/impl/CLibrary.java b/federation/sssd/src/main/java/org/jvnet/libpam/impl/CLibrary.java
new file mode 100644
index 0000000..e3b6105
--- /dev/null
+++ b/federation/sssd/src/main/java/org/jvnet/libpam/impl/CLibrary.java
@@ -0,0 +1,154 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package org.jvnet.libpam.impl;
+
+import com.sun.jna.Library;
+import com.sun.jna.Memory;
+import com.sun.jna.Native;
+import com.sun.jna.Platform;
+import com.sun.jna.Pointer;
+import com.sun.jna.Structure;
+import com.sun.jna.ptr.IntByReference;
+import org.jvnet.libpam.PAMException;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @author Kohsuke Kawaguchi
+ */
+public interface CLibrary extends Library {
+    /**
+     * Comparing http://linux.die.net/man/3/getpwnam
+     * and my Mac OS X reveals that the structure of this field isn't very portable.
+     * In particular, we cannot read the real name reliably.
+     */
+    public class passwd extends Structure {
+        /**
+         * User name.
+         */
+        public String pw_name;
+        /**
+         * Encrypted password.
+         */
+        public String pw_passwd;
+        public int pw_uid;
+        public int pw_gid;
+
+        // ... there are a lot more fields
+
+        public static passwd loadPasswd(String userName) throws PAMException {
+            passwd pwd = libc.getpwnam(userName);
+            if (pwd == null) {
+                throw new PAMException("No user information is available");
+            }
+            return pwd;
+        }
+
+        public String getPwName() {
+            return pw_name;
+        }
+
+        public String getPwPasswd() {
+            return pw_passwd;
+        }
+
+        public int getPwUid() {
+            return pw_uid;
+        }
+
+        public int getPwGid() {
+            return pw_gid;
+        }
+
+        public String getPwGecos() {
+            return null;
+        }
+
+        public String getPwDir() {
+            return null;
+        }
+
+        public String getPwShell() {
+            return null;
+        }
+
+        protected List getFieldOrder() {
+            return Arrays.asList("pw_name", "pw_passwd", "pw_uid", "pw_gid");
+        }
+    }
+
+    public class group extends Structure {
+        public String gr_name;
+        // ... the rest of the field is not interesting for us
+
+        protected List getFieldOrder() {
+            return Arrays.asList("gr_name");
+        }
+    }
+
+    Pointer calloc(int count, int size);
+
+    Pointer strdup(String s);
+
+    passwd getpwnam(String username);
+
+    /**
+     * Lists up group IDs of the given user. On Linux and most BSDs, but not on Solaris.
+     * See http://www.gnu.org/software/hello/manual/gnulib/getgrouplist.html
+     */
+    int getgrouplist(String user, int/*gid_t*/ group, Memory groups, IntByReference ngroups);
+
+    /**
+     * getgrouplist equivalent on Solaris.
+     * See http://mail.opensolaris.org/pipermail/sparks-discuss/2008-September/000528.html
+     */
+    int _getgroupsbymember(String user, Memory groups, int maxgids, int numgids);
+
+    group getgrgid(int/*gid_t*/ gid);
+
+    group getgrnam(String name);
+
+    // other user/group related functions that are likely useful
+    // see http://www.gnu.org/software/libc/manual/html_node/Users-and-Groups.html#Users-and-Groups
+
+
+    public static final CLibrary libc = Instance.init();
+
+    static class Instance {
+        private static CLibrary init() {
+            if (Platform.isMac() || Platform.isOpenBSD()) {
+                return (CLibrary) Native.loadLibrary("c", BSDCLibrary.class);
+            } else if (Platform.isFreeBSD()) {
+                return (CLibrary) Native.loadLibrary("c", FreeBSDCLibrary.class);
+            } else if (Platform.isSolaris()) {
+                return (CLibrary) Native.loadLibrary("c", SolarisCLibrary.class);
+            } else if (Platform.isLinux()) {
+                return (CLibrary) Native.loadLibrary("c", LinuxCLibrary.class);
+            } else {
+                return (CLibrary) Native.loadLibrary("c", CLibrary.class);
+            }
+        }
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/jvnet/libpam/impl/FreeBSDCLibrary.java b/federation/sssd/src/main/java/org/jvnet/libpam/impl/FreeBSDCLibrary.java
new file mode 100644
index 0000000..638aec2
--- /dev/null
+++ b/federation/sssd/src/main/java/org/jvnet/libpam/impl/FreeBSDCLibrary.java
@@ -0,0 +1,34 @@
+/*
+ *  The MIT License
+ *
+ *  Copyright 2014, R. Tyler Croy, Sun Microsystems, Inc.
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a copy
+ *  of this software and associated documentation files (the "Software"), to deal
+ *  in the Software without restriction, including without limitation the rights
+ *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ *  copies of the Software, and to permit persons to whom the Software is
+ *  furnished to do so, subject to the following conditions:
+ *
+ *  The above copyright notice and this permission notice shall be included in
+ *  all copies or substantial portions of the Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ *  THE SOFTWARE.
+ */
+
+package org.jvnet.libpam.impl;
+
+/**
+ * @author R. Tyler Croy
+ */
+public interface FreeBSDCLibrary extends CLibrary {
+
+    FreeBSDPasswd getpwnam(String username);
+
+}
                diff --git a/federation/sssd/src/main/java/org/jvnet/libpam/impl/FreeBSDPasswd.java b/federation/sssd/src/main/java/org/jvnet/libpam/impl/FreeBSDPasswd.java
new file mode 100644
index 0000000..28e519b
--- /dev/null
+++ b/federation/sssd/src/main/java/org/jvnet/libpam/impl/FreeBSDPasswd.java
@@ -0,0 +1,98 @@
+/*
+ *  The MIT License
+ *
+ *  Copyright 2014, R. Tyler Croy, Sun Microsystems, Inc.
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a copy
+ *  of this software and associated documentation files (the "Software"), to deal
+ *  in the Software without restriction, including without limitation the rights
+ *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ *  copies of the Software, and to permit persons to whom the Software is
+ *  furnished to do so, subject to the following conditions:
+ *
+ *  The above copyright notice and this permission notice shall be included in
+ *  all copies or substantial portions of the Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ *  THE SOFTWARE.
+ */
+
+package org.jvnet.libpam.impl;
+
+import org.jvnet.libpam.impl.CLibrary.passwd;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * FreeeBSD
+ * <p>
+ * struct passwd {
+ * char	*pw_name;
+ * char	*pw_passwd;
+ * uid_t	pw_uid;
+ * gid_t	pw_gid;
+ * time_t	pw_change;
+ * char	*pw_class;
+ * char	*pw_gecos;
+ * char	*pw_dir;
+ * char	*pw_shell;
+ * time_t	pw_expire;
+ * int	pw_fields;
+ * };
+ *
+ * @author R. Tyler Croy
+ */
+
+public class FreeBSDPasswd extends passwd {
+    /* password change time */
+    public long pw_change;
+
+    /* user access class */
+    public String pw_class;
+
+    /* Honeywell login info */
+    public String pw_gecos;
+
+    /* home directory */
+    public String pw_dir;
+
+    /* default shell */
+    public String pw_shell;
+
+    /* account expiration */
+    public long pw_expire;
+
+    /* internal on FreeBSD? */
+    public int pw_fields;
+
+    @Override
+    public String getPwGecos() {
+        return pw_gecos;
+    }
+
+    @Override
+    public String getPwDir() {
+        return pw_dir;
+    }
+
+    @Override
+    public String getPwShell() {
+        return pw_shell;
+    }
+
+    @Override
+    protected List getFieldOrder() {
+        List fieldOrder = new ArrayList(super.getFieldOrder());
+        fieldOrder.addAll(Arrays.asList("pw_change", "pw_class", "pw_gecos",
+                "pw_dir", "pw_shell", "pw_expire", "pw_fields"));
+        return fieldOrder;
+    }
+
+}
                diff --git a/federation/sssd/src/main/java/org/jvnet/libpam/impl/LinuxCLibrary.java b/federation/sssd/src/main/java/org/jvnet/libpam/impl/LinuxCLibrary.java
new file mode 100644
index 0000000..2525bbe
--- /dev/null
+++ b/federation/sssd/src/main/java/org/jvnet/libpam/impl/LinuxCLibrary.java
@@ -0,0 +1,34 @@
+/*
+ *  The MIT License
+ * 
+ *  Copyright 2011, Sun Microsystems, Inc.
+ * 
+ *  Permission is hereby granted, free of charge, to any person obtaining a copy
+ *  of this software and associated documentation files (the "Software"), to deal
+ *  in the Software without restriction, including without limitation the rights
+ *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ *  copies of the Software, and to permit persons to whom the Software is
+ *  furnished to do so, subject to the following conditions:
+ * 
+ *  The above copyright notice and this permission notice shall be included in
+ *  all copies or substantial portions of the Software.
+ * 
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ *  THE SOFTWARE.
+ */
+
+package org.jvnet.libpam.impl;
+
+/**
+ * @author Sebastian Sdorra
+ */
+public interface LinuxCLibrary extends CLibrary {
+
+    LinuxPasswd getpwnam(String username);
+
+}
                diff --git a/federation/sssd/src/main/java/org/jvnet/libpam/impl/LinuxPasswd.java b/federation/sssd/src/main/java/org/jvnet/libpam/impl/LinuxPasswd.java
new file mode 100644
index 0000000..c1b1678
--- /dev/null
+++ b/federation/sssd/src/main/java/org/jvnet/libpam/impl/LinuxPasswd.java
@@ -0,0 +1,81 @@
+/*
+ *  The MIT License
+ * 
+ *  Copyright 2011, Sun Microsystems, Inc.
+ * 
+ *  Permission is hereby granted, free of charge, to any person obtaining a copy
+ *  of this software and associated documentation files (the "Software"), to deal
+ *  in the Software without restriction, including without limitation the rights
+ *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ *  copies of the Software, and to permit persons to whom the Software is
+ *  furnished to do so, subject to the following conditions:
+ * 
+ *  The above copyright notice and this permission notice shall be included in
+ *  all copies or substantial portions of the Software.
+ * 
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ *  THE SOFTWARE.
+ */
+
+package org.jvnet.libpam.impl;
+
+import org.jvnet.libpam.impl.CLibrary.passwd;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Linux passwd
+ * <p>
+ * ?struct passwd
+ * {
+ * char *pw_name;
+ * char *pw_passwd;
+ * __uid_t pw_uid;
+ * __gid_t pw_gid;
+ * char *pw_gecos;
+ * char *pw_dir;
+ * char *pw_shell;
+ * };
+ *
+ * @author Sebastian Sdorra
+ */
+public class LinuxPasswd extends passwd {
+    /* Honeywell login info */
+    public String pw_gecos;
+
+    /* home directory */
+    public String pw_dir;
+
+    /* default shell */
+    public String pw_shell;
+
+
+    public String getPwGecos() {
+        return pw_gecos;
+    }
+
+    @Override
+    public String getPwDir() {
+        return pw_dir;
+    }
+
+    @Override
+    public String getPwShell() {
+        return pw_shell;
+    }
+
+    @Override
+    protected List getFieldOrder() {
+        List fieldOrder = new ArrayList(super.getFieldOrder());
+        fieldOrder.addAll(Arrays.asList("pw_gecos", "pw_dir", "pw_shell"));
+        return fieldOrder;
+    }
+
+}
                diff --git a/federation/sssd/src/main/java/org/jvnet/libpam/impl/PAMLibrary.java b/federation/sssd/src/main/java/org/jvnet/libpam/impl/PAMLibrary.java
new file mode 100644
index 0000000..a34ec31
--- /dev/null
+++ b/federation/sssd/src/main/java/org/jvnet/libpam/impl/PAMLibrary.java
@@ -0,0 +1,163 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package org.jvnet.libpam.impl;
+
+import com.sun.jna.Callback;
+import com.sun.jna.Library;
+import com.sun.jna.Native;
+import com.sun.jna.Pointer;
+import com.sun.jna.PointerType;
+import com.sun.jna.Structure;
+import com.sun.jna.ptr.PointerByReference;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.jvnet.libpam.impl.CLibrary.libc;
+
+/**
+ * libpam.so binding.
+ * <p>
+ * See http://www.opengroup.org/onlinepubs/008329799/apdxa.htm
+ * for the online reference of pam_appl.h
+ *
+ * @author Kohsuke Kawaguchi
+ */
+public interface PAMLibrary extends Library {
+    class pam_handle_t extends PointerType {
+        public pam_handle_t() {
+        }
+
+        public pam_handle_t(Pointer pointer) {
+            super(pointer);
+        }
+    }
+
+    class pam_message extends Structure {
+        public int msg_style;
+        public String msg;
+
+        /**
+         * Attach to the memory region pointed by the given pointer.
+         */
+        public pam_message(Pointer src) {
+            useMemory(src);
+            read();
+        }
+
+        protected List getFieldOrder() {
+            return Arrays.asList("msg_style", "msg");
+        }
+    }
+
+    class pam_response extends Structure {
+        /**
+         * This is really a string, but this field needs to be malloc-ed by the conversation
+         * method, and to be freed by the caler, so I bind it to {@link Pointer} here.
+         * <p>
+         * The man page doesn't say that, but see
+         * http://www.netbsd.org/docs/guide/en/chap-pam.html#pam-sample-conv
+         * This behavior is confirmed with a test, too; if I don't do strdup,
+         * libpam crashes.
+         */
+        public Pointer resp;
+        public int resp_retcode;
+
+        /**
+         * Attach to the memory region pointed by the given memory.
+         */
+        public pam_response(Pointer src) {
+            useMemory(src);
+            read();
+        }
+
+        public pam_response() {
+        }
+
+        /**
+         * Sets the response code.
+         */
+        public void setResp(String msg) {
+            this.resp = libc.strdup(msg);
+        }
+
+        protected List getFieldOrder() {
+            return Arrays.asList("resp", "resp_retcode");
+        }
+
+        public static final int SIZE = new pam_response().size();
+    }
+
+    class pam_conv extends Structure {
+        public interface PamCallback extends Callback {
+            /**
+             * According to http://www.netbsd.org/docs/guide/en/chap-pam.html#pam-sample-conv,
+             * resp and its member string both needs to be allocated by malloc,
+             * to be freed by the caller.
+             */
+            int callback(int num_msg, Pointer msg, Pointer resp, Pointer _);
+        }
+
+        public PamCallback conv;
+        public Pointer _;
+
+        public pam_conv(PamCallback conv) {
+            this.conv = conv;
+        }
+
+        protected List getFieldOrder() {
+            return Arrays.asList("conv", "_");
+        }
+    }
+
+    int pam_start(String service, String user, pam_conv conv, PointerByReference/* pam_handle_t** */ pamh_p);
+
+    int pam_end(pam_handle_t handle, int pam_status);
+
+    int pam_set_item(pam_handle_t handle, int item_type, String item);
+
+    int pam_get_item(pam_handle_t handle, int item_type, PointerByReference item);
+
+    int pam_authenticate(pam_handle_t handle, int flags);
+
+    int pam_setcred(pam_handle_t handle, int flags);
+
+    int pam_acct_mgmt(pam_handle_t handle, int flags);
+
+    String pam_strerror(pam_handle_t handle, int pam_error);
+
+    final int PAM_USER = 2;
+
+    // error code
+    final int PAM_SUCCESS = 0;
+    final int PAM_CONV_ERR = 6;
+
+
+    final int PAM_PROMPT_ECHO_OFF = 1; /* Echo off when getting response */
+    final int PAM_PROMPT_ECHO_ON = 2; /* Echo on when getting response */
+    final int PAM_ERROR_MSG = 3; /* Error message */
+    final int PAM_TEXT_INFO = 4; /* Textual information */
+
+    public static final PAMLibrary libpam = (PAMLibrary) Native.loadLibrary("pam", PAMLibrary.class);
+}
                diff --git a/federation/sssd/src/main/java/org/jvnet/libpam/impl/SolarisCLibrary.java b/federation/sssd/src/main/java/org/jvnet/libpam/impl/SolarisCLibrary.java
new file mode 100644
index 0000000..6b538a2
--- /dev/null
+++ b/federation/sssd/src/main/java/org/jvnet/libpam/impl/SolarisCLibrary.java
@@ -0,0 +1,35 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+
+package org.jvnet.libpam.impl;
+
+/**
+ * @author Sebastian Sdorra
+ */
+public interface SolarisCLibrary extends CLibrary {
+
+    SolarisPasswd getpwnam(String username);
+
+}
                diff --git a/federation/sssd/src/main/java/org/jvnet/libpam/impl/SolarisPasswd.java b/federation/sssd/src/main/java/org/jvnet/libpam/impl/SolarisPasswd.java
new file mode 100644
index 0000000..37ee749
--- /dev/null
+++ b/federation/sssd/src/main/java/org/jvnet/libpam/impl/SolarisPasswd.java
@@ -0,0 +1,86 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+
+package org.jvnet.libpam.impl;
+
+import org.jvnet.libpam.impl.CLibrary.passwd;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Solaris passwd
+ * <p>
+ * struct passwd {
+ * char    *pw_name;
+ * char    *pw_passwd;
+ * uid_t   pw_uid;
+ * gid_t   pw_gid;
+ * char    *pw_age;
+ * char    *pw_comment;
+ * char    *pw_gecos;
+ * char    *pw_dir;
+ * char    *pw_shell;
+ * };
+ *
+ * @author Sebastian Sdorra
+ */
+public class SolarisPasswd extends passwd {
+    public String pw_age;
+
+    public String pw_comment;
+
+    public String pw_gecos;
+
+    public String pw_dir;
+
+    public String pw_shell;
+
+
+    @Override
+    public String getPwGecos() {
+        return pw_gecos;
+    }
+
+    @Override
+    public String getPwDir() {
+        return pw_dir;
+    }
+
+    @Override
+    public String getPwShell() {
+        return pw_shell;
+    }
+
+    @Override
+    protected List getFieldOrder() {
+        List fieldOrder = new ArrayList(super.getFieldOrder());
+        fieldOrder.addAll(Arrays.asList("pw_age", "pw_comment", "pw_gecos",
+                "pw_dir", "pw_shell"));
+        return fieldOrder;
+    }
+
+}
                diff --git a/federation/sssd/src/main/java/org/jvnet/libpam/PAM.java b/federation/sssd/src/main/java/org/jvnet/libpam/PAM.java
new file mode 100644
index 0000000..7de5f90
--- /dev/null
+++ b/federation/sssd/src/main/java/org/jvnet/libpam/PAM.java
@@ -0,0 +1,188 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package org.jvnet.libpam;
+
+import com.sun.jna.Pointer;
+import com.sun.jna.ptr.PointerByReference;
+import org.jboss.logging.Logger;
+import org.jvnet.libpam.impl.CLibrary.passwd;
+import org.jvnet.libpam.impl.PAMLibrary.pam_conv;
+import org.jvnet.libpam.impl.PAMLibrary.pam_conv.PamCallback;
+import org.jvnet.libpam.impl.PAMLibrary.pam_handle_t;
+import org.jvnet.libpam.impl.PAMLibrary.pam_message;
+import org.jvnet.libpam.impl.PAMLibrary.pam_response;
+
+import java.util.Set;
+
+import static com.sun.jna.Native.POINTER_SIZE;
+import static org.jvnet.libpam.impl.CLibrary.libc;
+import static org.jvnet.libpam.impl.PAMLibrary.PAM_CONV_ERR;
+import static org.jvnet.libpam.impl.PAMLibrary.PAM_PROMPT_ECHO_OFF;
+import static org.jvnet.libpam.impl.PAMLibrary.PAM_SUCCESS;
+import static org.jvnet.libpam.impl.PAMLibrary.PAM_USER;
+import static org.jvnet.libpam.impl.PAMLibrary.libpam;
+
+/**
+ * PAM authenticator.
+ * <p>
+ * <p>
+ * Instances are thread unsafe and non reentrant. An instace cannot be reused
+ * to authenticate multiple users.
+ * <p>
+ * <p>
+ * For an overview of PAM programming, refer to the following resources:
+ * <p>
+ * <ul>
+ * <li><a href="http://www.netbsd.org/docs/guide/en/chap-pam.html">NetBSD PAM programming guide</a>
+ * <li><a href="http://www.kernel.org/pub/linux/libs/pam/">Linux PAM</a>
+ * </ul>
+ *
+ * @author Kohsuke Kawaguchi
+ */
+public class PAM {
+    private pam_handle_t pht;
+    private int ret;
+
+    /**
+     * Temporarily stored to pass a value from {@link #authenticate(String, String...)}
+     * to {@link pam_conv}.
+     */
+    private String[] factors;
+
+    /**
+     * Creates a new authenticator.
+     *
+     * @param serviceName PAM service name. This corresponds to the service name that shows up
+     *                    in the PAM configuration,
+     */
+    public PAM(String serviceName) throws PAMException {
+        pam_conv conv = new pam_conv(new PamCallback() {
+            public int callback(int num_msg, Pointer msg, Pointer resp, Pointer _) {
+                LOGGER.debug("pam_conv num_msg=" + num_msg);
+                if (factors == null)
+                    return PAM_CONV_ERR;
+
+                // allocates pam_response[num_msg]. the caller will free this
+                Pointer m = libc.calloc(pam_response.SIZE, num_msg);
+                resp.setPointer(0, m);
+
+                for (int i = 0; i < factors.length; i++) {
+                    pam_message pm = new pam_message(msg.getPointer(POINTER_SIZE * i));
+                    LOGGER.debug(pm.msg_style + ":" + pm.msg);
+                    if (pm.msg_style == PAM_PROMPT_ECHO_OFF) {
+                        pam_response r = new pam_response(m.share(pam_response.SIZE * i));
+                        r.setResp(factors[i]);
+                        r.write(); // write to (*resp)[i]
+                    }
+                }
+
+                return PAM_SUCCESS;
+            }
+        });
+
+        PointerByReference phtr = new PointerByReference();
+        check(libpam.pam_start(serviceName, null, conv, phtr), "pam_start failed");
+        pht = new pam_handle_t(phtr.getValue());
+    }
+
+    private void check(int ret, String msg) throws PAMException {
+        this.ret = ret;
+        if (ret != 0) {
+            if (pht != null)
+                throw new PAMException(msg + " : " + libpam.pam_strerror(pht, ret));
+            else
+                throw new PAMException(msg);
+        }
+    }
+
+    /**
+     * Authenticate the user with a password.
+     *
+     * @return Upon a successful authentication, return information about the user.
+     * @throws PAMException If the authentication fails.
+     */
+    public UnixUser authenticate(String username, String... factors) throws PAMException {
+        this.factors = factors;
+        try {
+            check(libpam.pam_set_item(pht, PAM_USER, username), "pam_set_item failed");
+            check(libpam.pam_authenticate(pht, 0), "pam_authenticate failed");
+            check(libpam.pam_setcred(pht, 0), "pam_setcred failed");
+            // several different error code seem to be used to represent authentication failures
+//            check(libpam.pam_acct_mgmt(pht,0),"pam_acct_mgmt failed");
+
+            PointerByReference r = new PointerByReference();
+            check(libpam.pam_get_item(pht, PAM_USER, r), "pam_get_item failed");
+            String userName = r.getValue().getString(0);
+            passwd pwd = libc.getpwnam(userName);
+            if (pwd == null)
+                throw new PAMException("Authentication succeeded but no user information is available");
+            return new UnixUser(userName, pwd);
+        } finally {
+            this.factors = null;
+        }
+    }
+
+    /**
+     * Returns the groups a user belongs to
+     *
+     * @param username
+     * @return Set of group names
+     * @throws PAMException
+     * @deprecated Pointless and ugly convenience method.
+     */
+    public Set<String> getGroupsOfUser(String username) throws PAMException {
+        return new UnixUser(username).getGroups();
+    }
+
+    /**
+     * After a successful authentication, call this method to obtain the effective user name.
+     * This can be different from the user name that you passed to the {@link #authenticate(String, String)}
+     * method.
+     */
+
+    /**
+     * Performs an early disposal of the object, instead of letting this GC-ed.
+     * Since PAM may hold on to native resources that don't put pressure on Java GC,
+     * doing this is a good idea.
+     * <p>
+     * <p>
+     * This method is called by {@link #finalize()}, too, so it's not required
+     * to call this method explicitly, however.
+     */
+    public void dispose() {
+        if (pht != null) {
+            libpam.pam_end(pht, ret);
+            pht = null;
+        }
+    }
+
+
+    @Override
+    protected void finalize() throws Throwable {
+        super.finalize();
+        dispose();
+    }
+
+    private static final Logger LOGGER = Logger.getLogger(PAM.class.getName());
+}
                diff --git a/federation/sssd/src/main/java/org/jvnet/libpam/PAMException.java b/federation/sssd/src/main/java/org/jvnet/libpam/PAMException.java
new file mode 100644
index 0000000..d26faf7
--- /dev/null
+++ b/federation/sssd/src/main/java/org/jvnet/libpam/PAMException.java
@@ -0,0 +1,48 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package org.jvnet.libpam;
+
+/**
+ * Exception in PAM invoactions.
+ *
+ * @author Kohsuke Kawaguchi
+ */
+public class PAMException extends Exception {
+    public PAMException() {
+    }
+
+    public PAMException(String message) {
+        super(message);
+    }
+
+    public PAMException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public PAMException(Throwable cause) {
+        super(cause);
+    }
+
+    private static final long serialVersionUID = 1L;
+}
                diff --git a/federation/sssd/src/main/java/org/jvnet/libpam/UnixUser.java b/federation/sssd/src/main/java/org/jvnet/libpam/UnixUser.java
new file mode 100644
index 0000000..bc1ceab
--- /dev/null
+++ b/federation/sssd/src/main/java/org/jvnet/libpam/UnixUser.java
@@ -0,0 +1,159 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package org.jvnet.libpam;
+
+import com.sun.jna.Memory;
+import com.sun.jna.ptr.IntByReference;
+import org.jvnet.libpam.impl.CLibrary.group;
+import org.jvnet.libpam.impl.CLibrary.passwd;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import static org.jvnet.libpam.impl.CLibrary.libc;
+
+/**
+ * Represents an Unix user. Immutable.
+ *
+ * @author Kohsuke Kawaguchi
+ */
+public class UnixUser {
+    private final String userName, gecos, dir, shell;
+    private final int uid, gid;
+    private final Set<String> groups;
+
+    /*package*/ UnixUser(String userName, passwd pwd) throws PAMException {
+        this.userName = userName;
+        this.gecos = pwd.getPwGecos();
+        this.dir = pwd.getPwDir();
+        this.shell = pwd.getPwShell();
+        this.uid = pwd.getPwUid();
+        this.gid = pwd.getPwGid();
+
+        int sz = 4; /*sizeof(gid_t)*/
+
+        int ngroups = 64;
+        Memory m = new Memory(ngroups * sz);
+        IntByReference pngroups = new IntByReference(ngroups);
+        try {
+            if (libc.getgrouplist(userName, pwd.getPwGid(), m, pngroups) < 0) {
+                // allocate a bigger memory
+                m = new Memory(pngroups.getValue() * sz);
+                if (libc.getgrouplist(userName, pwd.getPwGid(), m, pngroups) < 0)
+                    // shouldn't happen, but just in case.
+                    throw new PAMException("getgrouplist failed");
+            }
+            ngroups = pngroups.getValue();
+        } catch (LinkageError e) {
+            // some platform, notably Solaris, doesn't have the getgrouplist function
+            ngroups = libc._getgroupsbymember(userName, m, ngroups, 0);
+            if (ngroups < 0)
+                throw new PAMException("_getgroupsbymember failed");
+        }
+
+        groups = new HashSet<String>();
+        for (int i = 0; i < ngroups; i++) {
+            int gid = m.getInt(i * sz);
+            group grp = libc.getgrgid(gid);
+            if (grp == null) {
+                continue;
+            }
+            groups.add(grp.gr_name);
+        }
+    }
+
+    public UnixUser(String userName) throws PAMException {
+        this(userName, passwd.loadPasswd(userName));
+    }
+
+    /**
+     * Copy constructor for mocking. Not intended for regular use. Only for testing.
+     * This signature may change in the future.
+     */
+    protected UnixUser(String userName, String gecos, String dir, String shell, int uid, int gid, Set<String> groups) {
+        this.userName = userName;
+        this.gecos = gecos;
+        this.dir = dir;
+        this.shell = shell;
+        this.uid = uid;
+        this.gid = gid;
+        this.groups = groups;
+    }
+
+    /**
+     * Gets the unix account name. Never null.
+     */
+    public String getUserName() {
+        return userName;
+    }
+
+    /**
+     * Gets the UID of this user.
+     */
+    public int getUID() {
+        return uid;
+    }
+
+    /**
+     * Gets the GID of this user.
+     */
+    public int getGID() {
+        return gid;
+    }
+
+    /**
+     * Gets the gecos (the real name) of this user.
+     */
+    public String getGecos() {
+        return gecos;
+    }
+
+    /**
+     * Gets the home directory of this user.
+     */
+    public String getDir() {
+        return dir;
+    }
+
+    /**
+     * Gets the shell of this user.
+     */
+    public String getShell() {
+        return shell;
+    }
+
+    /**
+     * Gets the groups that this user belongs to.
+     *
+     * @return never null.
+     */
+    public Set<String> getGroups() {
+        return Collections.unmodifiableSet(groups);
+    }
+
+    public static boolean exists(String name) {
+        return libc.getpwnam(name) != null;
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/keycloak/federation/sssd/api/Sssd.java b/federation/sssd/src/main/java/org/keycloak/federation/sssd/api/Sssd.java
new file mode 100644
index 0000000..a5bb57a
--- /dev/null
+++ b/federation/sssd/src/main/java/org/keycloak/federation/sssd/api/Sssd.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.federation.sssd.api;
+
+import org.freedesktop.dbus.DBusConnection;
+import org.freedesktop.dbus.Variant;
+import org.freedesktop.dbus.exceptions.DBusException;
+import org.freedesktop.sssd.infopipe.InfoPipe;
+import org.freedesktop.sssd.infopipe.User;
+import org.jboss.logging.Logger;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Vector;
+
+/**
+ * @author <a href="mailto:bruno@abstractj.org">Bruno Oliveira</a>
+ * @version $Revision: 1 $
+ */
+public class Sssd {
+
+    public static final String BUSNAME = "org.freedesktop.sssd.infopipe";
+
+    public static User user() {
+        return SingletonHolder.USER_OBJECT;
+    }
+
+    public static InfoPipe infopipe() {
+        return SingletonHolder.INFOPIPE_OBJECT;
+    }
+
+    public static void disconnect() {
+        SingletonHolder.DBUS_CONNECTION.disconnect();
+    }
+
+    private String username;
+    private static final Logger logger = Logger.getLogger(Sssd.class);
+
+    private Sssd() {
+    }
+
+    public Sssd(String username) {
+        this.username = username;
+    }
+
+    private static final class SingletonHolder {
+        private static InfoPipe INFOPIPE_OBJECT;
+        private static User USER_OBJECT;
+        private static DBusConnection DBUS_CONNECTION;
+
+        static {
+            try {
+                DBUS_CONNECTION = DBusConnection.getConnection(DBusConnection.SYSTEM);
+                INFOPIPE_OBJECT = DBUS_CONNECTION.getRemoteObject(BUSNAME, InfoPipe.OBJECTPATH, InfoPipe.class);
+                USER_OBJECT = DBUS_CONNECTION.getRemoteObject(BUSNAME, User.OBJECTPATH, User.class);
+            } catch (DBusException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    public static String getRawAttribute(Variant variant) {
+        if (variant != null) {
+            Vector value = (Vector) variant.getValue();
+            if (value.size() >= 1) {
+                return value.get(0).toString();
+            }
+        }
+        return null;
+    }
+
+    public Map<String, Variant> getUserAttributes() {
+        String[] attr = {"mail", "givenname", "sn", "telephoneNumber"};
+        Map<String, Variant> attributes = null;
+        try {
+            InfoPipe infoPipe = infopipe();
+            attributes = infoPipe.getUserAttributes(username, Arrays.asList(attr));
+        } catch (Exception e) {
+            logger.error("Failed to retrieve user's attributes from SSSD", e);
+        }
+
+        return attributes;
+    }
+
+    public List<String> getUserGroups() {
+        List<String> userGroups = null;
+        try {
+            InfoPipe infoPipe = Sssd.infopipe();
+            userGroups = infoPipe.getUserGroups(username);
+        } catch (Exception e) {
+            logger.error("Failed to retrieve user's groups from SSSD", e);
+        }
+        return userGroups;
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/keycloak/federation/sssd/impl/PAMAuthenticator.java b/federation/sssd/src/main/java/org/keycloak/federation/sssd/impl/PAMAuthenticator.java
new file mode 100644
index 0000000..f982201
--- /dev/null
+++ b/federation/sssd/src/main/java/org/keycloak/federation/sssd/impl/PAMAuthenticator.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.federation.sssd.impl;
+
+import org.jboss.logging.Logger;
+import org.jvnet.libpam.PAM;
+import org.jvnet.libpam.PAMException;
+import org.jvnet.libpam.UnixUser;
+
+/**
+ * PAMAuthenticator for Unix users
+ *
+ * @author <a href="mailto:bruno@abstractj.org">Bruno Oliveira</a>
+ * @version $Revision: 1 $
+ */
+public class PAMAuthenticator {
+
+    private static final String PAM_SERVICE = "keycloak";
+    private static final Logger logger = Logger.getLogger(PAMAuthenticator.class);
+    private final String username;
+    private final String[] factors;
+
+    public PAMAuthenticator(String username, String... factors) {
+        this.username = username;
+        this.factors = factors;
+    }
+
+    /**
+     * Returns true if user was successfully authenticated against PAM
+     *
+     * @return UnixUser object if user was successfully authenticated
+     */
+    public UnixUser authenticate() {
+        PAM pam = null;
+        UnixUser user = null;
+        try {
+            pam = new PAM(PAM_SERVICE);
+            user = pam.authenticate(username, factors);
+        } catch (PAMException e) {
+            logger.error("Authentication failed", e);
+            e.printStackTrace();
+        } finally {
+            pam.dispose();
+        }
+        return user;
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/keycloak/federation/sssd/ReadonlySSSDUserModelDelegate.java b/federation/sssd/src/main/java/org/keycloak/federation/sssd/ReadonlySSSDUserModelDelegate.java
new file mode 100755
index 0000000..52061c9
--- /dev/null
+++ b/federation/sssd/src/main/java/org/keycloak/federation/sssd/ReadonlySSSDUserModelDelegate.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.federation.sssd;
+
+import org.keycloak.models.ModelReadOnlyException;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserCredentialValueModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.utils.UserModelDelegate;
+
+/**
+ * Readonly proxy for a SSSD UserModel that prevents attributes from being updated.
+ *
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @author <a href="mailto:bruno@abstractj.org">Bruno Oliveira</a>
+ * @version $Revision: 1 $
+ */
+public class ReadonlySSSDUserModelDelegate extends UserModelDelegate implements UserModel {
+
+    private final SSSDFederationProvider provider;
+
+    public ReadonlySSSDUserModelDelegate(UserModel delegate, SSSDFederationProvider provider) {
+        super(delegate);
+        this.provider = provider;
+    }
+
+    @Override
+    public void setUsername(String username) {
+        throw new ModelReadOnlyException("Federated storage is not writable");
+    }
+
+    @Override
+    public void setLastName(String lastName) {
+        throw new ModelReadOnlyException("Federated storage is not writable");
+    }
+
+    @Override
+    public void setFirstName(String first) {
+        throw new ModelReadOnlyException("Federated storage is not writable");
+    }
+
+    @Override
+    public void updateCredentialDirectly(UserCredentialValueModel cred) {
+        if (cred.getType().equals(UserCredentialModel.PASSWORD)) {
+            throw new IllegalStateException("Federated storage is not writable");
+        }
+        super.updateCredentialDirectly(cred);
+    }
+
+    @Override
+    public void updateCredential(UserCredentialModel cred) {
+        if (provider.getSupportedCredentialTypes(delegate).contains(cred.getType())) {
+            throw new ModelReadOnlyException("Federated storage is not writable");
+        }
+        delegate.updateCredential(cred);
+    }
+
+    @Override
+    public void setEmail(String email) {
+        throw new ModelReadOnlyException("Federated storage is not writable");
+    }
+}
                diff --git a/federation/sssd/src/main/java/org/keycloak/federation/sssd/SSSDFederationProvider.java b/federation/sssd/src/main/java/org/keycloak/federation/sssd/SSSDFederationProvider.java
new file mode 100755
index 0000000..a9089ec
--- /dev/null
+++ b/federation/sssd/src/main/java/org/keycloak/federation/sssd/SSSDFederationProvider.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.federation.sssd;
+
+import org.freedesktop.dbus.Variant;
+import org.jboss.logging.Logger;
+import org.keycloak.federation.sssd.api.Sssd;
+import org.keycloak.federation.sssd.impl.PAMAuthenticator;
+import org.keycloak.models.CredentialValidationOutput;
+import org.keycloak.models.GroupModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserFederationProvider;
+import org.keycloak.models.UserFederationProviderModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.services.managers.UserManager;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * SPI provider implementation to retrieve data from SSSD and authenticate
+ * against PAM
+ *
+ * @author <a href="mailto:bruno@abstractj.org">Bruno Oliveira</a>
+ * @version $Revision: 1 $
+ */
+public class SSSDFederationProvider implements UserFederationProvider {
+
+    private static final Logger logger = Logger.getLogger(SSSDFederationProvider.class);
+
+    protected static final Set<String> supportedCredentialTypes = new HashSet<>();
+    private final SSSDFederationProviderFactory factory;
+    protected KeycloakSession session;
+    protected UserFederationProviderModel model;
+
+    public SSSDFederationProvider(KeycloakSession session, UserFederationProviderModel model, SSSDFederationProviderFactory sssdFederationProviderFactory) {
+        this.session = session;
+        this.model = model;
+        this.factory = sssdFederationProviderFactory;
+    }
+
+    static {
+        supportedCredentialTypes.add(UserCredentialModel.PASSWORD);
+    }
+
+
+    @Override
+    public UserModel getUserByUsername(RealmModel realm, String username) {
+        return findOrCreateAuthenticatedUser(realm, username);
+    }
+
+    /**
+     * Called after successful authentication
+     *
+     * @param realm    realm
+     * @param username username without realm prefix
+     * @return user if found or successfully created. Null if user with same username already exists, but is not linked to this provider
+     */
+    protected UserModel findOrCreateAuthenticatedUser(RealmModel realm, String username) {
+        UserModel user = session.userStorage().getUserByUsername(username, realm);
+        if (user != null) {
+            logger.debug("SSSD authenticated user " + username + " found in Keycloak storage");
+
+            if (!model.getId().equals(user.getFederationLink())) {
+                logger.warn("User with username " + username + " already exists, but is not linked to provider [" + model.getDisplayName() + "]");
+                return null;
+            } else {
+                UserModel proxied = validateAndProxy(realm, user);
+                if (proxied != null) {
+                    return proxied;
+                } else {
+                    logger.warn("User with username " + username + " already exists and is linked to provider [" + model.getDisplayName() +
+                            "] but principal is not correct.");
+                    logger.warn("Will re-create user");
+                    new UserManager(session).removeUser(realm, user, session.userStorage());
+                }
+            }
+        }
+
+        logger.debug("SSSD authenticated user " + username + " not in Keycloak storage. Creating...");
+        return importUserToKeycloak(realm, username);
+    }
+
+    protected UserModel importUserToKeycloak(RealmModel realm, String username) {
+        Sssd sssd = new Sssd(username);
+        Map<String, Variant> sssdUser = sssd.getUserAttributes();
+        logger.debugf("Creating SSSD user: %s to local Keycloak storage", username);
+        UserModel user = session.userStorage().addUser(realm, username);
+        user.setEnabled(true);
+        user.setEmail(Sssd.getRawAttribute(sssdUser.get("mail")));
+        user.setFirstName(Sssd.getRawAttribute(sssdUser.get("givenname")));
+        user.setLastName(Sssd.getRawAttribute(sssdUser.get("sn")));
+        for (String s : sssd.getUserGroups()) {
+            GroupModel group = KeycloakModelUtils.findGroupByPath(realm, "/" + s);
+            if (group == null) {
+                group = session.realms().createGroup(realm, s);
+            }
+            user.joinGroup(group);
+        }
+        user.setFederationLink(model.getId());
+        return validateAndProxy(realm, user);
+    }
+
+    @Override
+    public UserModel getUserByEmail(RealmModel realm, String email) {
+        return null;
+    }
+
+    @Override
+    public List<UserModel> searchByAttributes(Map<String, String> attributes, RealmModel realm, int maxResults) {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults) {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public void preRemove(RealmModel realm) {
+        // complete  We don't care about the realm being removed
+    }
+
+    @Override
+    public void preRemove(RealmModel realm, RoleModel role) {
+        // complete we dont'care if a role is removed
+
+    }
+
+    @Override
+    public void preRemove(RealmModel realm, GroupModel group) {
+        // complete we dont'care if a role is removed
+
+    }
+
+    @Override
+    public boolean isValid(RealmModel realm, UserModel local) {
+        Map<String, Variant> attributes = new Sssd(local.getUsername()).getUserAttributes();
+        return Sssd.getRawAttribute(attributes.get("mail")).equalsIgnoreCase(local.getEmail());
+    }
+
+    @Override
+    public Set<String> getSupportedCredentialTypes(UserModel user) {
+        return supportedCredentialTypes;
+    }
+
+    @Override
+    public Set<String> getSupportedCredentialTypes() {
+        return supportedCredentialTypes;
+    }
+
+    @Override
+    public boolean validCredentials(RealmModel realm, UserModel user, List<UserCredentialModel> input) {
+        for (UserCredentialModel cred : input) {
+            if (cred.getType().equals(UserCredentialModel.PASSWORD)) {
+                PAMAuthenticator pam = factory.createPAMAuthenticator(user.getUsername(), cred.getValue());
+                return (pam.authenticate() != null);
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public boolean validCredentials(RealmModel realm, UserModel user, UserCredentialModel... input) {
+        return validCredentials(realm, user, Arrays.asList(input));
+    }
+
+    @Override
+    public CredentialValidationOutput validCredentials(RealmModel realm, UserCredentialModel credential) {
+        return CredentialValidationOutput.failed();
+    }
+
+    @Override
+    public UserModel validateAndProxy(RealmModel realm, UserModel local) {
+        if (isValid(realm, local)) {
+            return new ReadonlySSSDUserModelDelegate(local, this);
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public boolean synchronizeRegistrations() {
+        return false;
+    }
+
+    @Override
+    public UserModel register(RealmModel realm, UserModel user) {
+        throw new IllegalStateException("Registration not supported");
+    }
+
+    @Override
+    public boolean removeUser(RealmModel realm, UserModel user) {
+        return true;
+    }
+
+    @Override
+    public void close() {
+        Sssd.disconnect();
+    }
+}
                diff --git a/federation/sssd/src/main/resources/DBUS-JAVA-AUTHORS b/federation/sssd/src/main/resources/DBUS-JAVA-AUTHORS
new file mode 100644
index 0000000..9b7699e
--- /dev/null
+++ b/federation/sssd/src/main/resources/DBUS-JAVA-AUTHORS
@@ -0,0 +1,37 @@
+The D-Bus Java implementation was written by:
+
+Matthew Johnson <dbus -at matthew -dot- ath -dot- cx>
+
+Bug fixes/reports and other suggestions from:
+
+Remi Emonet <remi.emonet -at- inrialpes -dot- fr>
+Simon McVittie <simon -dot- mcvittie -at- collabora -dot- co -dot- uk>
+Dick Hollenbeck <dick -at- softplc -dot- com> 
+Joshua Nichols <nichoj -at- gentoo -dot- org>
+Ralf Kistner <ralf.kistner -at- gmail -dot- com>
+Henrik Petander <henrik -dot- petander -at- iki -dot- fi>
+Luigi Paioro <luigi -at- lambrate -dot- it>
+Roberto Francisco Arroyo Moreno <robfram -at- ugr -dot- es>
+Steve Crane <Steve -dot Crane -at- rococosoft -dot- com>
+Philippe Marschall <philippe -dot- marschall -at- gmail -dot- com>
+Daniel Machado <cdanielmachado -at- gmail -dot- com>
+Anibal Sanchez <anibal -dot- sanchez -at- sunya -dot- com -dot- ar>
+Jan Kümmel <freedesktop -at- snorc -dot- org>
+Johannes Felten <johannesfelten -at- googlemail -dot- com>
+Tom Walsh <walshtc -at- gmail -dot- com>
+Ed Wei <Edward.Wei.03 -at- alum -dot- dartmouth -dot- org>
+Sveinung Kvilhaugsvik <sveinung84 -at- users -dot- sourceforge -dot- net>
+Hugues Moreau <hmoreau -at- gmail -dot- com>
+Viktar Vauchkevich <vctr -at- yandex -dot- ru>
+Serkan Kaba <serkan_kaba -at- yahoo -dot- com>
+Adam Bennett <cruxic -at- gmail -dot- com>
+Frank Benoit <benoit -at- tionex -dot- de>
+Gunnar Aastrand Grimnes <gunnar -dot- grimnes -at- dfki -dot- de>
+
+The included Viewer application was originally written by:
+
+Peter Cox <petercox -at- gawab -dot- com>
+
+with patches from:
+
+Zsombor Gegesy <gzsombor -at- gmail -dot- com>
                federation/sssd/src/main/resources/DBUS-JAVA-LICENSE 680(+680 -0)
diff --git a/federation/sssd/src/main/resources/DBUS-JAVA-LICENSE b/federation/sssd/src/main/resources/DBUS-JAVA-LICENSE
new file mode 100644
index 0000000..d651143
--- /dev/null
+++ b/federation/sssd/src/main/resources/DBUS-JAVA-LICENSE
@@ -0,0 +1,680 @@
+The D-Bus Java implementation is licensed to you under your choice of the
+Academic Free License version 2.1, or the GNU Lesser/Library General Public License
+version 2.  Both licenses are included here. Each source code file is marked
+with the proper copyright information.
+
+The Academic Free License
+v. 2.1
+
+This Academic Free License (the "License") applies to any original work of
+authorship (the "Original Work") whose owner (the "Licensor") has placed the
+following notice immediately following the copyright notice for the Original
+Work:
+
+Licensed under the Academic Free License version 2.1
+
+1) Grant of Copyright License. Licensor hereby grants You a world-wide,
+royalty-free, non-exclusive, perpetual, sublicenseable license to do the
+following:
+
+a) to reproduce the Original Work in copies;
+
+b) to prepare derivative works ("Derivative Works") based upon the Original
+Work;
+
+c) to distribute copies of the Original Work and Derivative Works to the
+public;
+
+d) to perform the Original Work publicly; and
+
+e) to display the Original Work publicly.
+
+2) Grant of Patent License. Licensor hereby grants You a world-wide,
+royalty-free, non-exclusive, perpetual, sublicenseable license, under patent
+claims owned or controlled by the Licensor that are embodied in the Original
+Work as furnished by the Licensor, to make, use, sell and offer for sale the
+Original Work and Derivative Works.
+
+3) Grant of Source Code License. The term "Source Code" means the preferred
+form of the Original Work for making modifications to it and all available
+documentation describing how to modify the Original Work. Licensor hereby
+agrees to provide a machine-readable copy of the Source Code of the Original
+Work along with each copy of the Original Work that Licensor distributes.
+Licensor reserves the right to satisfy this obligation by placing a
+machine-readable copy of the Source Code in an information repository
+reasonably calculated to permit inexpensive and convenient access by You for as
+long as Licensor continues to distribute the Original Work, and by publishing
+the address of that information repository in a notice immediately following
+the copyright notice that applies to the Original Work.
+
+4) Exclusions From License Grant. Neither the names of Licensor, nor the names
+of any contributors to the Original Work, nor any of their trademarks or
+service marks, may be used to endorse or promote products derived from this
+Original Work without express prior written permission of the Licensor. Nothing
+in this License shall be deemed to grant any rights to trademarks, copyrights,
+patents, trade secrets or any other intellectual property of Licensor except as
+expressly stated herein. No patent license is granted to make, use, sell or
+offer to sell embodiments of any patent claims other than the licensed claims
+defined in Section 2. No right is granted to the trademarks of Licensor even if
+such marks are included in the Original Work. Nothing in this License shall be
+interpreted to prohibit Licensor from licensing under different terms from this
+License any Original Work that Licensor otherwise would have a right to
+license.
+
+5) This section intentionally omitted.
+
+6) Attribution Rights. You must retain, in the Source Code of any Derivative
+Works that You create, all copyright, patent or trademark notices from the
+Source Code of the Original Work, as well as any notices of licensing and any
+descriptive text identified therein as an "Attribution Notice." You must cause
+the Source Code for any Derivative Works that You create to carry a prominent
+Attribution Notice reasonably calculated to inform recipients that You have
+modified the Original Work.
+
+7) Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that
+the copyright in and to the Original Work and the patent rights granted herein
+by Licensor are owned by the Licensor or are sublicensed to You under the terms
+of this License with the permission of the contributor(s) of those copyrights
+and patent rights. Except as expressly stated in the immediately proceeding
+sentence, the Original Work is provided under this License on an "AS IS" BASIS
+and WITHOUT WARRANTY, either express or implied, including, without limitation,
+the warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU.
+This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No
+license to Original Work is granted hereunder except under this disclaimer.
+
+8) Limitation of Liability. Under no circumstances and under no legal theory,
+whether in tort (including negligence), contract, or otherwise, shall the
+Licensor be liable to any person for any direct, indirect, special, incidental,
+or consequential damages of any character arising as a result of this License
+or the use of the Original Work including, without limitation, damages for loss
+of goodwill, work stoppage, computer failure or malfunction, or any and all
+other commercial damages or losses. This limitation of liability shall not
+apply to liability for death or personal injury resulting from Licensor's
+negligence to the extent applicable law prohibits such limitation. Some
+jurisdictions do not allow the exclusion or limitation of incidental or
+consequential damages, so this exclusion and limitation may not apply to You.
+
+9) Acceptance and Termination. If You distribute copies of the Original Work or
+a Derivative Work, You must make a reasonable effort under the circumstances to
+obtain the express assent of recipients to the terms of this License. Nothing
+else but this License (or another written agreement between Licensor and You)
+grants You permission to create Derivative Works based upon the Original Work
+or to exercise any of the rights granted in Section 1 herein, and any attempt
+to do so except under the terms of this License (or another written agreement
+between Licensor and You) is expressly prohibited by U.S. copyright law, the
+equivalent laws of other countries, and by international treaty. Therefore, by
+exercising any of the rights granted to You in Section 1 herein, You indicate
+Your acceptance of this License and all of its terms and conditions.
+
+10) Termination for Patent Action. This License shall terminate automatically
+and You may no longer exercise any of the rights granted to You by this License
+as of the date You commence an action, including a cross-claim or counterclaim,
+against Licensor or any licensee alleging that the Original Work infringes a
+patent. This termination provision shall not apply for an action alleging
+patent infringement by combinations of the Original Work with other software or
+hardware.
+
+11) Jurisdiction, Venue and Governing Law. Any action or suit relating to this
+License may be brought only in the courts of a jurisdiction wherein the
+Licensor resides or in which Licensor conducts its primary business, and under
+the laws of that jurisdiction excluding its conflict-of-law provisions. The
+application of the United Nations Convention on Contracts for the International
+Sale of Goods is expressly excluded. Any use of the Original Work outside the
+scope of this License or after its termination shall be subject to the
+requirements and penalties of the U.S. Copyright Act, 17 U.S.C. § 101 et seq.,
+the equivalent laws of other countries, and international treaty. This section
+shall survive the termination of this License.
+
+12) Attorneys Fees. In any action to enforce the terms of this License or
+seeking damages relating thereto, the prevailing party shall be entitled to
+recover its costs and expenses, including, without limitation, reasonable
+attorneys' fees and costs incurred in connection with such action, including
+any appeal of such action. This section shall survive the termination of this
+License.
+
+13) Miscellaneous. This License represents the complete agreement concerning
+the subject matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent necessary to
+make it enforceable.
+
+14) Definition of "You" in This License. "You" throughout this License, whether
+in upper or lower case, means an individual or a legal entity exercising rights
+under, and complying with all of the terms of, this License. For legal
+entities, "You" includes any entity that controls, is controlled by, or is
+under common control with you. For purposes of this definition, "control" means
+(i) the power, direct or indirect, to cause the direction or management of such
+entity, whether by contract or otherwise, or (ii) ownership of fifty percent
+(50%) or more of the outstanding shares, or (iii) beneficial ownership of such
+entity.
+
+15) Right to Use. You may use the Original Work in all ways not otherwise
+restricted or conditioned by this License or by law, and Licensor promises not
+to interfere with or be responsible for such uses by You.
+
+This license is Copyright (C) 2003-2004 Lawrence E. Rosen. All rights reserved.
+Permission is hereby granted to copy and distribute this license without
+modification. This license may not be modified without the express written
+permission of its copyright owner.
+
+
+-- 
+END OF ACADEMIC FREE LICENSE. The following is intended to describe the
+essential differences between the Academic Free License (AFL) version 1.0 and
+other open source licenses:
+
+The Academic Free License is similar to the BSD, MIT, UoI/NCSA and Apache
+licenses in many respects but it is intended to solve a few problems with those
+licenses.
+    
+* The AFL is written so as to make it clear what software is being 
+licensed (by the inclusion of a statement following the copyright notice in the
+software). This way, the license functions better than a template license. The
+BSD, MIT and UoI/NCSA licenses apply to unidentified software.
+    
+* The AFL contains a complete copyright grant to the software. The BSD 
+and Apache licenses are vague and incomplete in that respect.
+    
+* The AFL contains a complete patent grant to the software. The BSD, MIT, 
+UoI/NCSA and Apache licenses rely on an implied patent license and contain no
+explicit patent grant.
+    
+* The AFL makes it clear that no trademark rights are granted to the 
+licensor's trademarks. The Apache license contains such a provision, but the
+BSD, MIT and UoI/NCSA licenses do not.
+    
+* The AFL includes the warranty by the licensor that it either owns the 
+copyright or that it is distributing the software under a license. None of the
+other licenses contain that warranty. All other warranties are disclaimed, as
+is the case for the other licenses.
+
+* The AFL is itself copyrighted (with the right granted to copy and distribute 
+without modification). This ensures that the owner of the copyright to the
+license will control changes. The Apache license contains a copyright notice,
+but the BSD, MIT and UoI/NCSA licenses do not.
+
+-- 
+START OF GNU LIBRARY GENERAL PUBLIC LICENSE 
+--
+
+		  GNU LIBRARY GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+		    51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+
+		  GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
                diff --git a/federation/sssd/src/main/resources/en_US.properties b/federation/sssd/src/main/resources/en_US.properties
new file mode 100644
index 0000000..31bc06c
--- /dev/null
+++ b/federation/sssd/src/main/resources/en_US.properties
@@ -0,0 +1,82 @@
+#java-format
+notBasicType=" is not a basic type"
+notObjectProvidedByProcess=" is not an object provided by this process."
+arrayOutOfBounds="Array index out of bounds, paofs={0}, pabuf.length={1}, buf.length={2}."
+arrayMustNotExceed="Arrays must not exceed "
+asyncCallNoReply="Async call has not had a reply"
+busAddressBlank="Bus address is blank"
+busAddressInvalid="Bus address is invalid: "
+cannotWrapNullInVariant="Can't wrap Null in a Variant"
+cannotWrapMultiValuedInVariant="Can't wrap a multi-valued type in a Variant: "
+cannotWrapNoTypesInVariant="Can't wrap multiple or no types in a Variant: "
+cannotWrapUnqualifiedVariant="Can't wrap {0} in an unqualified Variant ({1})."
+cannotResolveSessionBusAddress="Cannot Resolve Session Bus Address"
+cannotWatchSignalsWellKnownBussName="Cannot watch for signals based on well known bus name as source, only unique names."
+cannotCreateClassFromSignal="Could not create class from signal "
+interfaceToCastNotFound="Could not find an interface to cast to"
+interfaceNotAllowedOutsidePackage="DBusInterfaces cannot be declared outside a package"
+interfaceMustBeDefinedPackage="DBusInterfaces must be defined in a package."
+disconnected="Disconnected"
+errorExecutingMethod="Error Executing Method {0}.{1}: {2}"
+errorDeserializingMessage="Error deserializing message: number of parameters didn't match receiving signature"
+nonExportableParameterizedType="Exporting non-exportable parameterized type "
+nonExportableType "Exporting non-exportable type "
+errorAddSignalParameters="Failed to add signal parameters: "
+errorAuth="Failed to auth"
+connectionFailure="Failed to connect to bus "
+contructDBusTypeFailure="Failed to construct D-Bus type: "
+constructOutgoingMethodCallFailure="Failed to construct outgoing method call: "
+createProxyExportFailure="Failed to create proxy object for {0} exported by {1}. Reason: {2}"
+createProxyFailure="Failed to create proxy object for {0}; reason: {1}."
+parseDBusTypeSignatureFailure="Failed to parse DBus type signature: "
+parseDBusSignatureFailure="Failed to parse DBus type signature: {0} ({1})."
+dbusRegistrationFailure="Failed to register bus name"
+deSerializationFailure="Failure in de-serializing message: "
+introspectInterfaceExceedCharacters="Introspected interface name exceeds 255 characters. Cannot export objects of type "
+introspectMethodExceedCharacters="Introspected method name exceeds 255 characters. Cannot export objects with method "
+introspectSignalExceedCharacters="Introspected signal name exceeds 255 characters. Cannot export objects with signals of type "
+invalidBusType="Invalid Bus Type: "
+invalidCommand="Invalid Command "
+invalidBusName="Invalid bus name"
+nullBusName="Invalid bus name: null"
+invalidObjectPath="Invalid object path: "
+nullObjectPath="Invalid object path: null"
+invalidTypeMatchRule="Invalid type for match rule: "
+mapParameters="Map must have 2 parameters"
+messageFailedSend="Message Failed to Send: "
+messageTypeUnsupported="Message type {0} unsupported"
+multiValuedArrayNotPermitted="Multi-valued array types not permitted"
+missingObjectPath="Must Specify an Object Path"
+missingDestinationPathFunction="Must specify destination, path and function name to MethodCalls."
+missingErrorName="Must specify error name to Errors."
+missingPathInterfaceSignal="Must specify object path, interface and signal name to Signals."
+notReplyWithSpecifiedTime="No reply within specified time"
+missingTransport="No transport present"
+notDBusInterface="Not A DBus Interface"
+notDBusSignal="Not A DBus Signal"
+convertionTypeNotExpected="Not An Expected Convertion type from {0} to {1}"
+notConnected="Not Connected"
+notPrimitiveType="Not a primitive type"
+invalidDBusCode="Not a valid D-Bus type code: "
+invalidWrapperType="Not a wrapper type"
+invalidArray="Not an array"
+objectNotExportedNoRemoteSpecified="Not an object exported by this connection and no remote specified"
+notEnoughElementsToCreateCustomObject="Not enough elements to create custom object from serialized data ({0} < {1})."
+objectAlreadyExported="Object already exported"
+arraySentAsNonPrimitive="Primative array being sent as non-primative array."
+protocolVersionUnsupported="Protocol version {0} is unsupported"
+cannotIntrospectReturnType="Return type of Object[] cannot be introspected properly"
+mustImplementDeserializeMethod="Serializable classes must implement a deserialize method"
+mustSerializeNativeDBusTypes="Serializable classes must serialize to native DBus types"
+signalsMustBeMemberOfClass="Signals must be declared as a member of a class implementing DBusInterface which is the member of a package."
+spuriousReply="Spurious reply. No message with the given serial id was awaiting a reply."
+utf8NotSupported="System does not support UTF-8 encoding"
+methodDoesNotExist="The method `{0}.{1}' does not exist on this object."
+unconvertableType="Trying to marshall to unconvertable type (from {0} to {1})."
+transportReturnedEOF="Underlying transport returned EOF"
+waitingFor="Waiting for: "
+invalidReturnType="Wrong return type (failed to de-serialize correct types: {0} )"
+voidReturnType="Wrong return type (got void, expected a value)"
+tupleReturnType="Wrong return type (not expecting Tuple)"
+unknownAddress="unknown address type "
+isNotBetween="{0} is not between {1} and {2}."
                diff --git a/federation/sssd/src/main/resources/META-INF/services/org.keycloak.models.UserFederationProviderFactory b/federation/sssd/src/main/resources/META-INF/services/org.keycloak.models.UserFederationProviderFactory
new file mode 100644
index 0000000..d06ece1
--- /dev/null
+++ b/federation/sssd/src/main/resources/META-INF/services/org.keycloak.models.UserFederationProviderFactory
@@ -0,0 +1,18 @@
+#
+# Copyright 2016 Red Hat, Inc. and/or its affiliates
+# and other contributors as indicated by the @author tags.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+org.keycloak.federation.sssd.SSSDFederationProviderFactory
\ No newline at end of file
                diff --git a/federation/sssd/src/test/java/cx/ath/matthew/unix/testclient.java b/federation/sssd/src/test/java/cx/ath/matthew/unix/testclient.java
new file mode 100644
index 0000000..2acef18
--- /dev/null
+++ b/federation/sssd/src/test/java/cx/ath/matthew/unix/testclient.java
@@ -0,0 +1,49 @@
+/*
+ * Java Unix Sockets Library
+ *
+ * Copyright (c) Matthew Johnson 2005
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ * 
+ * To Contact the author, please email src@matthew.ath.cx
+ *
+ */
+
+package cx.ath.matthew.unix;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+
+public class testclient {
+    public static void main(String args[]) throws IOException {
+        UnixSocket s = new UnixSocket(new UnixSocketAddress("testsock", true));
+        OutputStream os = s.getOutputStream();
+        PrintWriter o = new PrintWriter(os);
+        BufferedReader r = new BufferedReader(new InputStreamReader(System.in));
+        String l;
+        while (null != (l = r.readLine())) {
+            byte[] buf = (l + "\n").getBytes();
+            os.write(buf, 0, buf.length);
+        }
+        s.close();
+    }
+}
                diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/cross_test_client.java b/federation/sssd/src/test/java/org/freedesktop/dbus/cross_test_client.java
new file mode 100644
index 0000000..b71033d
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/cross_test_client.java
@@ -0,0 +1,511 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import cx.ath.matthew.debug.Debug;
+import org.freedesktop.DBus;
+import org.freedesktop.dbus.exceptions.DBusException;
+import org.freedesktop.dbus.exceptions.DBusExecutionException;
+import org.freedesktop.dbus.types.DBusMapType;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.Vector;
+
+public class cross_test_client implements DBus.Binding.TestClient, DBusSigHandler<DBus.Binding.TestSignals.Triggered> {
+    private DBusConnection conn;
+    private static Set<String> passed = new TreeSet<String>();
+    private static Map<String, List<String>> failed = new HashMap<String, List<String>>();
+    private static cross_test_client ctc;
+
+    static {
+        List<String> l = new Vector<String>();
+        l.add("Signal never arrived");
+        failed.put("org.freedesktop.DBus.Binding.TestSignals.Triggered", l);
+        l = new Vector<String>();
+        l.add("Method never called");
+        failed.put("org.freedesktop.DBus.Binding.TestClient.Response", l);
+    }
+
+    public cross_test_client(DBusConnection conn) {
+        this.conn = conn;
+    }
+
+    public boolean isRemote() {
+        return false;
+    }
+
+    public void handle(DBus.Binding.TestSignals.Triggered t) {
+        failed.remove("org.freedesktop.DBus.Binding.TestSignals.Triggered");
+        if (new UInt64(21389479283L).equals(t.a) && "/Test".equals(t.getPath()))
+            pass("org.freedesktop.DBus.Binding.TestSignals.Triggered");
+        else if (!new UInt64(21389479283L).equals(t.a))
+            fail("org.freedesktop.DBus.Binding.TestSignals.Triggered", "Incorrect signal content; expected 21389479283 got " + t.a);
+        else if (!"/Test".equals(t.getPath()))
+            fail("org.freedesktop.DBus.Binding.TestSignals.Triggered", "Incorrect signal source object; expected /Test got " + t.getPath());
+    }
+
+    public void Response(UInt16 a, double b) {
+        failed.remove("org.freedesktop.DBus.Binding.TestClient.Response");
+        if (a.equals(new UInt16(15)) && (b == 12.5))
+            pass("org.freedesktop.DBus.Binding.TestClient.Response");
+        else
+            fail("org.freedesktop.DBus.Binding.TestClient.Response", "Incorrect parameters; expected 15, 12.5 got " + a + ", " + b);
+    }
+
+    public static void pass(String test) {
+        passed.add(test.replaceAll("[$]", ""));
+    }
+
+    public static void fail(String test, String reason) {
+        test = test.replaceAll("[$]", "");
+        List<String> reasons = failed.get(test);
+        if (null == reasons) {
+            reasons = new Vector<String>();
+            failed.put(test, reasons);
+        }
+        reasons.add(reason);
+    }
+
+    @SuppressWarnings("unchecked")
+    public static void test(Class<? extends DBusInterface> iface, Object proxy, String method, Object rv, Object... parameters) {
+        try {
+            Method[] ms = iface.getMethods();
+            Method m = null;
+            for (Method t : ms) {
+                if (t.getName().equals(method))
+                    m = t;
+            }
+            Object o = m.invoke(proxy, parameters);
+
+            String msg = "Incorrect return value; sent ( ";
+            if (null != parameters)
+                for (Object po : parameters)
+                    if (null != po)
+                        msg += collapseArray(po) + ",";
+            msg = msg.replaceAll(".$", ");");
+            msg += " expected " + collapseArray(rv) + " got " + collapseArray(o);
+
+            if (null != rv && rv.getClass().isArray()) {
+                compareArray(iface.getName() + "" + method, rv, o);
+            } else if (rv instanceof Map) {
+                if (o instanceof Map) {
+                    Map<Object, Object> a = (Map<Object, Object>) o;
+                    Map<Object, Object> b = (Map<Object, Object>) rv;
+                    if (a.keySet().size() != b.keySet().size()) {
+                        fail(iface.getName() + "" + method, msg);
+                    } else for (Object k : a.keySet())
+                        if (a.get(k) instanceof List) {
+                            if (b.get(k) instanceof List)
+                                if (setCompareLists((List<Object>) a.get(k), (List<Object>) b.get(k)))
+                                    ;
+                                else
+                                    fail(iface.getName() + "" + method, msg);
+                            else
+                                fail(iface.getName() + "" + method, msg);
+                        } else if (!a.get(k).equals(b.get(k))) {
+                            fail(iface.getName() + "" + method, msg);
+                            return;
+                        }
+                    pass(iface.getName() + "" + method);
+                } else
+                    fail(iface.getName() + "" + method, msg);
+            } else {
+                if (o == rv || (o != null && o.equals(rv)))
+                    pass(iface.getName() + "" + method);
+                else
+                    fail(iface.getName() + "" + method, msg);
+            }
+        } catch (DBusExecutionException DBEe) {
+            DBEe.printStackTrace();
+            fail(iface.getName() + "" + method, "Error occurred during execution: " + DBEe.getClass().getName() + " " + DBEe.getMessage());
+        } catch (InvocationTargetException ITe) {
+            ITe.printStackTrace();
+            fail(iface.getName() + "" + method, "Error occurred during execution: " + ITe.getCause().getClass().getName() + " " + ITe.getCause().getMessage());
+        } catch (Exception e) {
+            e.printStackTrace();
+            fail(iface.getName() + "" + method, "Error occurred during execution: " + e.getClass().getName() + " " + e.getMessage());
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public static String collapseArray(Object array) {
+        if (null == array) return "null";
+        if (array.getClass().isArray()) {
+            String s = "{ ";
+            for (int i = 0; i < Array.getLength(array); i++)
+                s += collapseArray(Array.get(array, i)) + ",";
+            s = s.replaceAll(".$", " }");
+            return s;
+        } else if (array instanceof List) {
+            String s = "{ ";
+            for (Object o : (List<Object>) array)
+                s += collapseArray(o) + ",";
+            s = s.replaceAll(".$", " }");
+            return s;
+        } else if (array instanceof Map) {
+            String s = "{ ";
+            for (Object o : ((Map<Object, Object>) array).keySet())
+                s += collapseArray(o) + " => " + collapseArray(((Map<Object, Object>) array).get(o)) + ",";
+            s = s.replaceAll(".$", " }");
+            return s;
+        } else return array.toString();
+    }
+
+    public static <T> boolean setCompareLists(List<T> a, List<T> b) {
+        if (a.size() != b.size()) return false;
+        for (Object v : a)
+            if (!b.contains(v)) return false;
+        return true;
+    }
+
+    @SuppressWarnings("unchecked")
+    public static List<Variant<Object>> PrimitizeRecurse(Object a, Type t) {
+        List<Variant<Object>> vs = new Vector<Variant<Object>>();
+        if (t instanceof ParameterizedType) {
+            Class<Object> c = (Class<Object>) ((ParameterizedType) t).getRawType();
+            if (List.class.isAssignableFrom(c)) {
+                Object os;
+                if (a instanceof List)
+                    os = ((List<Object>) a).toArray();
+                else
+                    os = a;
+                Type[] ts = ((ParameterizedType) t).getActualTypeArguments();
+                for (int i = 0; i < Array.getLength(os); i++)
+                    vs.addAll(PrimitizeRecurse(Array.get(os, i), ts[0]));
+            } else if (Map.class.isAssignableFrom(c)) {
+                Object[] os = ((Map) a).keySet().toArray();
+                Object[] ks = ((Map) a).values().toArray();
+                Type[] ts = ((ParameterizedType) t).getActualTypeArguments();
+                for (int i = 0; i < ks.length; i++)
+                    vs.addAll(PrimitizeRecurse(ks[i], ts[0]));
+                for (int i = 0; i < os.length; i++)
+                    vs.addAll(PrimitizeRecurse(os[i], ts[1]));
+            } else if (Struct.class.isAssignableFrom(c)) {
+                Object[] os = ((Struct) a).getParameters();
+                Type[] ts = ((ParameterizedType) t).getActualTypeArguments();
+                for (int i = 0; i < os.length; i++)
+                    vs.addAll(PrimitizeRecurse(os[i], ts[i]));
+
+            } else if (Variant.class.isAssignableFrom(c)) {
+                vs.addAll(PrimitizeRecurse(((Variant) a).getValue(), ((Variant) a).getType()));
+            }
+        } else if (Variant.class.isAssignableFrom((Class) t))
+            vs.addAll(PrimitizeRecurse(((Variant) a).getValue(), ((Variant) a).getType()));
+        else if (t instanceof Class && ((Class) t).isArray()) {
+            Type t2 = ((Class) t).getComponentType();
+            for (int i = 0; i < Array.getLength(a); i++)
+                vs.addAll(PrimitizeRecurse(Array.get(a, i), t2));
+        } else vs.add(new Variant(a));
+
+        return vs;
+    }
+
+    @SuppressWarnings("unchecked")
+    public static List<Variant<Object>> Primitize(Variant<Object> a) {
+        return PrimitizeRecurse(a.getValue(), a.getType());
+    }
+
+    @SuppressWarnings("unchecked")
+    public static void primitizeTest(DBus.Binding.Tests tests, Object input) {
+        Variant<Object> in = new Variant<Object>(input);
+        List<Variant<Object>> vs = Primitize(in);
+        List<Variant<Object>> res;
+
+        try {
+
+            res = tests.Primitize(in);
+            if (setCompareLists(res, vs))
+                pass("org.freedesktop.DBus.Binding.Tests.Primitize");
+            else
+                fail("org.freedesktop.DBus.Binding.Tests.Primitize", "Wrong Return Value; expected " + collapseArray(vs) + " got " + collapseArray(res));
+
+        } catch (Exception e) {
+            if (Debug.debug) Debug.print(e);
+            fail("org.freedesktop.DBus.Binding.Tests.Primitize", "Exception occurred during test: (" + e.getClass().getName() + ") " + e.getMessage());
+        }
+    }
+
+    public static void doTests(DBus.Peer peer, DBus.Introspectable intro, DBus.Introspectable rootintro, DBus.Binding.Tests tests, DBus.Binding.SingleTests singletests) {
+        Random r = new Random();
+        int i;
+        test(DBus.Peer.class, peer, "Ping", null);
+
+        try {
+            if (intro.Introspect().startsWith("<!DOCTYPE")) pass("org.freedesktop.DBus.Introspectable.Introspect");
+            else
+                fail("org.freedesktop.DBus.Introspectable.Introspect", "Didn't get valid xml data back when introspecting /Test");
+        } catch (DBusExecutionException DBEe) {
+            if (Debug.debug) Debug.print(DBEe);
+            fail("org.freedesktop.DBus.Introspectable.Introspect", "Got exception during introspection on /Test (" + DBEe.getClass().getName() + "): " + DBEe.getMessage());
+        }
+
+        try {
+            if (rootintro.Introspect().startsWith("<!DOCTYPE")) pass("org.freedesktop.DBus.Introspectable.Introspect");
+            else
+                fail("org.freedesktop.DBus.Introspectable.Introspect", "Didn't get valid xml data back when introspecting /");
+        } catch (DBusExecutionException DBEe) {
+            if (Debug.debug) Debug.print(DBEe);
+            fail("org.freedesktop.DBus.Introspectable.Introspect", "Got exception during introspection on / (" + DBEe.getClass().getName() + "): " + DBEe.getMessage());
+        }
+
+        test(DBus.Binding.Tests.class, tests, "Identity", new Variant<Integer>(new Integer(1)), new Variant<Integer>(new Integer(1)));
+        test(DBus.Binding.Tests.class, tests, "Identity", new Variant<String>("Hello"), new Variant<String>("Hello"));
+
+        test(DBus.Binding.Tests.class, tests, "IdentityBool", false, false);
+        test(DBus.Binding.Tests.class, tests, "IdentityBool", true, true);
+
+        test(DBus.Binding.Tests.class, tests, "Invert", false, true);
+        test(DBus.Binding.Tests.class, tests, "Invert", true, false);
+
+        test(DBus.Binding.Tests.class, tests, "IdentityByte", (byte) 0, (byte) 0);
+        test(DBus.Binding.Tests.class, tests, "IdentityByte", (byte) 1, (byte) 1);
+        test(DBus.Binding.Tests.class, tests, "IdentityByte", (byte) -1, (byte) -1);
+        test(DBus.Binding.Tests.class, tests, "IdentityByte", Byte.MAX_VALUE, Byte.MAX_VALUE);
+        test(DBus.Binding.Tests.class, tests, "IdentityByte", Byte.MIN_VALUE, Byte.MIN_VALUE);
+        i = r.nextInt();
+        test(DBus.Binding.Tests.class, tests, "IdentityByte", (byte) i, (byte) i);
+
+        test(DBus.Binding.Tests.class, tests, "IdentityInt16", (short) 0, (short) 0);
+        test(DBus.Binding.Tests.class, tests, "IdentityInt16", (short) 1, (short) 1);
+        test(DBus.Binding.Tests.class, tests, "IdentityInt16", (short) -1, (short) -1);
+        test(DBus.Binding.Tests.class, tests, "IdentityInt16", Short.MAX_VALUE, Short.MAX_VALUE);
+        test(DBus.Binding.Tests.class, tests, "IdentityInt16", Short.MIN_VALUE, Short.MIN_VALUE);
+        i = r.nextInt();
+        test(DBus.Binding.Tests.class, tests, "IdentityInt16", (short) i, (short) i);
+
+        test(DBus.Binding.Tests.class, tests, "IdentityInt32", 0, 0);
+        test(DBus.Binding.Tests.class, tests, "IdentityInt32", 1, 1);
+        test(DBus.Binding.Tests.class, tests, "IdentityInt32", -1, -1);
+        test(DBus.Binding.Tests.class, tests, "IdentityInt32", Integer.MAX_VALUE, Integer.MAX_VALUE);
+        test(DBus.Binding.Tests.class, tests, "IdentityInt32", Integer.MIN_VALUE, Integer.MIN_VALUE);
+        i = r.nextInt();
+        test(DBus.Binding.Tests.class, tests, "IdentityInt32", i, i);
+
+
+        test(DBus.Binding.Tests.class, tests, "IdentityInt64", (long) 0, (long) 0);
+        test(DBus.Binding.Tests.class, tests, "IdentityInt64", (long) 1, (long) 1);
+        test(DBus.Binding.Tests.class, tests, "IdentityInt64", (long) -1, (long) -1);
+        test(DBus.Binding.Tests.class, tests, "IdentityInt64", Long.MAX_VALUE, Long.MAX_VALUE);
+        test(DBus.Binding.Tests.class, tests, "IdentityInt64", Long.MIN_VALUE, Long.MIN_VALUE);
+        i = r.nextInt();
+        test(DBus.Binding.Tests.class, tests, "IdentityInt64", (long) i, (long) i);
+
+        test(DBus.Binding.Tests.class, tests, "IdentityUInt16", new UInt16(0), new UInt16(0));
+        test(DBus.Binding.Tests.class, tests, "IdentityUInt16", new UInt16(1), new UInt16(1));
+        test(DBus.Binding.Tests.class, tests, "IdentityUInt16", new UInt16(UInt16.MAX_VALUE), new UInt16(UInt16.MAX_VALUE));
+        test(DBus.Binding.Tests.class, tests, "IdentityUInt16", new UInt16(UInt16.MIN_VALUE), new UInt16(UInt16.MIN_VALUE));
+        i = r.nextInt();
+        i = i > 0 ? i : -i;
+        test(DBus.Binding.Tests.class, tests, "IdentityUInt16", new UInt16(i % UInt16.MAX_VALUE), new UInt16(i % UInt16.MAX_VALUE));
+
+        test(DBus.Binding.Tests.class, tests, "IdentityUInt32", new UInt32(0), new UInt32(0));
+        test(DBus.Binding.Tests.class, tests, "IdentityUInt32", new UInt32(1), new UInt32(1));
+        test(DBus.Binding.Tests.class, tests, "IdentityUInt32", new UInt32(UInt32.MAX_VALUE), new UInt32(UInt32.MAX_VALUE));
+        test(DBus.Binding.Tests.class, tests, "IdentityUInt32", new UInt32(UInt32.MIN_VALUE), new UInt32(UInt32.MIN_VALUE));
+        i = r.nextInt();
+        i = i > 0 ? i : -i;
+        test(DBus.Binding.Tests.class, tests, "IdentityUInt32", new UInt32(i % UInt32.MAX_VALUE), new UInt32(i % UInt32.MAX_VALUE));
+
+        test(DBus.Binding.Tests.class, tests, "IdentityUInt64", new UInt64(0), new UInt64(0));
+        test(DBus.Binding.Tests.class, tests, "IdentityUInt64", new UInt64(1), new UInt64(1));
+        test(DBus.Binding.Tests.class, tests, "IdentityUInt64", new UInt64(UInt64.MAX_LONG_VALUE), new UInt64(UInt64.MAX_LONG_VALUE));
+        test(DBus.Binding.Tests.class, tests, "IdentityUInt64", new UInt64(UInt64.MAX_BIG_VALUE), new UInt64(UInt64.MAX_BIG_VALUE));
+        test(DBus.Binding.Tests.class, tests, "IdentityUInt64", new UInt64(UInt64.MIN_VALUE), new UInt64(UInt64.MIN_VALUE));
+        i = r.nextInt();
+        i = i > 0 ? i : -i;
+        test(DBus.Binding.Tests.class, tests, "IdentityUInt64", new UInt64(i % UInt64.MAX_LONG_VALUE), new UInt64(i % UInt64.MAX_LONG_VALUE));
+
+        test(DBus.Binding.Tests.class, tests, "IdentityDouble", 0.0, 0.0);
+        test(DBus.Binding.Tests.class, tests, "IdentityDouble", 1.0, 1.0);
+        test(DBus.Binding.Tests.class, tests, "IdentityDouble", -1.0, -1.0);
+        test(DBus.Binding.Tests.class, tests, "IdentityDouble", Double.MAX_VALUE, Double.MAX_VALUE);
+        test(DBus.Binding.Tests.class, tests, "IdentityDouble", Double.MIN_VALUE, Double.MIN_VALUE);
+        i = r.nextInt();
+        test(DBus.Binding.Tests.class, tests, "IdentityDouble", (double) i, (double) i);
+
+        test(DBus.Binding.Tests.class, tests, "IdentityString", "", "");
+        test(DBus.Binding.Tests.class, tests, "IdentityString", "The Quick Brown Fox Jumped Over The Lazy Dog", "The Quick Brown Fox Jumped Over The Lazy Dog");
+        test(DBus.Binding.Tests.class, tests, "IdentityString", "ひらがなゲーム - かなぶん", "ひらがなゲーム - かなぶん");
+
+        testArray(DBus.Binding.Tests.class, tests, "IdentityBoolArray", Boolean.TYPE, null);
+        testArray(DBus.Binding.Tests.class, tests, "IdentityByteArray", Byte.TYPE, null);
+        testArray(DBus.Binding.Tests.class, tests, "IdentityInt16Array", Short.TYPE, null);
+        testArray(DBus.Binding.Tests.class, tests, "IdentityInt32Array", Integer.TYPE, null);
+        testArray(DBus.Binding.Tests.class, tests, "IdentityInt64Array", Long.TYPE, null);
+        testArray(DBus.Binding.Tests.class, tests, "IdentityDoubleArray", Double.TYPE, null);
+
+        testArray(DBus.Binding.Tests.class, tests, "IdentityArray", Variant.class, new Variant<String>("aoeu"));
+        testArray(DBus.Binding.Tests.class, tests, "IdentityUInt16Array", UInt16.class, new UInt16(12));
+        testArray(DBus.Binding.Tests.class, tests, "IdentityUInt32Array", UInt32.class, new UInt32(190));
+        testArray(DBus.Binding.Tests.class, tests, "IdentityUInt64Array", UInt64.class, new UInt64(103948));
+        testArray(DBus.Binding.Tests.class, tests, "IdentityStringArray", String.class, "asdf");
+
+        int[] is = new int[0];
+        test(DBus.Binding.Tests.class, tests, "Sum", 0L, is);
+        r = new Random();
+        int len = (r.nextInt() % 100) + 15;
+        len = (len < 0 ? -len : len) + 15;
+        is = new int[len];
+        long result = 0;
+        for (i = 0; i < len; i++) {
+            is[i] = r.nextInt();
+            result += is[i];
+        }
+        test(DBus.Binding.Tests.class, tests, "Sum", result, is);
+
+        byte[] bs = new byte[0];
+        test(DBus.Binding.SingleTests.class, singletests, "Sum", new UInt32(0), bs);
+        len = (r.nextInt() % 100);
+        len = (len < 0 ? -len : len) + 15;
+        bs = new byte[len];
+        int res = 0;
+        for (i = 0; i < len; i++) {
+            bs[i] = (byte) r.nextInt();
+            res += (bs[i] < 0 ? bs[i] + 256 : bs[i]);
+        }
+        test(DBus.Binding.SingleTests.class, singletests, "Sum", new UInt32(res % (UInt32.MAX_VALUE + 1)), bs);
+
+        test(DBus.Binding.Tests.class, tests, "DeStruct", new DBus.Binding.Triplet<String, UInt32, Short>("hi", new UInt32(12), new Short((short) 99)), new DBus.Binding.TestStruct("hi", new UInt32(12), new Short((short) 99)));
+
+        Map<String, String> in = new HashMap<String, String>();
+        Map<String, List<String>> out = new HashMap<String, List<String>>();
+        test(DBus.Binding.Tests.class, tests, "InvertMapping", out, in);
+
+        in.put("hi", "there");
+        in.put("to", "there");
+        in.put("from", "here");
+        in.put("in", "out");
+        List<String> l = new Vector<String>();
+        l.add("hi");
+        l.add("to");
+        out.put("there", l);
+        l = new Vector<String>();
+        l.add("from");
+        out.put("here", l);
+        l = new Vector<String>();
+        l.add("in");
+        out.put("out", l);
+        test(DBus.Binding.Tests.class, tests, "InvertMapping", out, in);
+
+        primitizeTest(tests, new Integer(1));
+        primitizeTest(tests,
+                new Variant<Variant<Variant<Variant<String>>>>(
+                        new Variant<Variant<Variant<String>>>(
+                                new Variant<Variant<String>>(
+                                        new Variant<String>("Hi")))));
+        primitizeTest(tests, new Variant<Map<String, String>>(in, new DBusMapType(String.class, String.class)));
+
+        test(DBus.Binding.Tests.class, tests, "Trigger", null, "/Test", new UInt64(21389479283L));
+
+        try {
+            ctc.conn.sendSignal(new DBus.Binding.TestClient.Trigger("/Test", new UInt16(15), 12.5));
+        } catch (DBusException DBe) {
+            if (Debug.debug) Debug.print(DBe);
+            throw new DBusExecutionException(DBe.getMessage());
+        }
+
+        try {
+            Thread.sleep(10000);
+        } catch (InterruptedException Ie) {
+        }
+
+        test(DBus.Binding.Tests.class, tests, "Exit", null);
+    }
+
+    public static void testArray(Class<? extends DBusInterface> iface, Object proxy, String method, Class<? extends Object> arrayType, Object content) {
+        Object array = Array.newInstance(arrayType, 0);
+        test(iface, proxy, method, array, array);
+        Random r = new Random();
+        int l = (r.nextInt() % 100);
+        array = Array.newInstance(arrayType, (l < 0 ? -l : l) + 15);
+        if (null != content)
+            Arrays.fill((Object[]) array, content);
+        test(iface, proxy, method, array, array);
+    }
+
+    public static void compareArray(String test, Object a, Object b) {
+        if (!a.getClass().equals(b.getClass())) {
+            fail(test, "Incorrect return type; expected " + a.getClass() + " got " + b.getClass());
+            return;
+        }
+        boolean pass = false;
+
+        if (a instanceof Object[])
+            pass = Arrays.equals((Object[]) a, (Object[]) b);
+        else if (a instanceof byte[])
+            pass = Arrays.equals((byte[]) a, (byte[]) b);
+        else if (a instanceof boolean[])
+            pass = Arrays.equals((boolean[]) a, (boolean[]) b);
+        else if (a instanceof int[])
+            pass = Arrays.equals((int[]) a, (int[]) b);
+        else if (a instanceof short[])
+            pass = Arrays.equals((short[]) a, (short[]) b);
+        else if (a instanceof long[])
+            pass = Arrays.equals((long[]) a, (long[]) b);
+        else if (a instanceof double[])
+            pass = Arrays.equals((double[]) a, (double[]) b);
+
+        if (pass)
+            pass(test);
+        else {
+            String s = "Incorrect return value; expected ";
+            s += collapseArray(a);
+            s += " got ";
+            s += collapseArray(b);
+            fail(test, s);
+        }
+    }
+
+    public static void main(String[] args) {
+        try {
+      /* init */
+            DBusConnection conn = DBusConnection.getConnection(DBusConnection.SESSION);
+            ctc = new cross_test_client(conn);
+            conn.exportObject("/Test", ctc);
+            conn.addSigHandler(DBus.Binding.TestSignals.Triggered.class, ctc);
+            DBus.Binding.Tests tests = conn.getRemoteObject("org.freedesktop.DBus.Binding.TestServer", "/Test", DBus.Binding.Tests.class);
+            DBus.Binding.SingleTests singletests = conn.getRemoteObject("org.freedesktop.DBus.Binding.TestServer", "/Test", DBus.Binding.SingleTests.class);
+            DBus.Peer peer = conn.getRemoteObject("org.freedesktop.DBus.Binding.TestServer", "/Test", DBus.Peer.class);
+            DBus.Introspectable intro = conn.getRemoteObject("org.freedesktop.DBus.Binding.TestServer", "/Test", DBus.Introspectable.class);
+
+            DBus.Introspectable rootintro = conn.getRemoteObject("org.freedesktop.DBus.Binding.TestServer", "/", DBus.Introspectable.class);
+
+            doTests(peer, intro, rootintro, tests, singletests);
+
+      /* report results */
+            for (String s : passed)
+                System.out.println(s + " pass");
+            int i = 1;
+            for (String s : failed.keySet())
+                for (String r : failed.get(s)) {
+                    System.out.println(s + " fail " + i);
+                    System.out.println("report " + i + ": " + r);
+                    i++;
+                }
+
+            conn.disconnect();
+        } catch (DBusException DBe) {
+            DBe.printStackTrace();
+            System.exit(1);
+        }
+    }
+}
                diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/cross_test_server.java b/federation/sssd/src/test/java/org/freedesktop/dbus/cross_test_server.java
new file mode 100644
index 0000000..61bba4a
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/cross_test_server.java
@@ -0,0 +1,342 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.DBus;
+import org.freedesktop.dbus.exceptions.DBusException;
+import org.freedesktop.dbus.exceptions.DBusExecutionException;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.Vector;
+
+public class cross_test_server implements DBus.Binding.Tests, DBus.Binding.SingleTests, DBusSigHandler<DBus.Binding.TestClient.Trigger> {
+    private DBusConnection conn;
+    boolean run = true;
+    private Set<String> done = new TreeSet<String>();
+    private Set<String> notdone = new TreeSet<String>();
+
+    {
+        notdone.add("org.freedesktop.DBus.Binding.Tests.Identity");
+        notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityByte");
+        notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityBool");
+        notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityInt16");
+        notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityUInt16");
+        notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityInt32");
+        notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityUInt32");
+        notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityInt64");
+        notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityUInt64");
+        notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityDouble");
+        notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityString");
+        notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityArray");
+        notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityByteArray");
+        notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityBoolArray");
+        notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityInt16Array");
+        notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityUInt16Array");
+        notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityInt32Array");
+        notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityUInt32Array");
+        notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityInt64Array");
+        notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityUInt64Array");
+        notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityDoubleArray");
+        notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityStringArray");
+        notdone.add("org.freedesktop.DBus.Binding.Tests.Sum");
+        notdone.add("org.freedesktop.DBus.Binding.SingleTests.Sum");
+        notdone.add("org.freedesktop.DBus.Binding.Tests.InvertMapping");
+        notdone.add("org.freedesktop.DBus.Binding.Tests.DeStruct");
+        notdone.add("org.freedesktop.DBus.Binding.Tests.Primitize");
+        notdone.add("org.freedesktop.DBus.Binding.Tests.Invert");
+        notdone.add("org.freedesktop.DBus.Binding.Tests.Trigger");
+        notdone.add("org.freedesktop.DBus.Binding.Tests.Exit");
+        notdone.add("org.freedesktop.DBus.Binding.TestClient.Trigger");
+    }
+
+    public cross_test_server(DBusConnection conn) {
+        this.conn = conn;
+    }
+
+    public boolean isRemote() {
+        return false;
+    }
+
+    @SuppressWarnings("unchecked")
+    @DBus.Description("Returns whatever it is passed")
+    public <T> Variant<T> Identity(Variant<T> input) {
+        done.add("org.freedesktop.DBus.Binding.Tests.Identity");
+        notdone.remove("org.freedesktop.DBus.Binding.Tests.Identity");
+        return new Variant(input.getValue());
+    }
+
+    @DBus.Description("Returns whatever it is passed")
+    public byte IdentityByte(byte input) {
+        done.add("org.freedesktop.DBus.Binding.Tests.IdentityByte");
+        notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityByte");
+        return input;
+    }
+
+    @DBus.Description("Returns whatever it is passed")
+    public boolean IdentityBool(boolean input) {
+        done.add("org.freedesktop.DBus.Binding.Tests.IdentityBool");
+        notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityBool");
+        return input;
+    }
+
+    @DBus.Description("Returns whatever it is passed")
+    public short IdentityInt16(short input) {
+        done.add("org.freedesktop.DBus.Binding.Tests.IdentityInt16");
+        notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityInt16");
+        return input;
+    }
+
+    @DBus.Description("Returns whatever it is passed")
+    public UInt16 IdentityUInt16(UInt16 input) {
+        done.add("org.freedesktop.DBus.Binding.Tests.IdentityUInt16");
+        notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityUInt16");
+        return input;
+    }
+
+    @DBus.Description("Returns whatever it is passed")
+    public int IdentityInt32(int input) {
+        done.add("org.freedesktop.DBus.Binding.Tests.IdentityInt32");
+        notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityInt32");
+        return input;
+    }
+
+    @DBus.Description("Returns whatever it is passed")
+    public UInt32 IdentityUInt32(UInt32 input) {
+        done.add("org.freedesktop.DBus.Binding.Tests.IdentityUInt32");
+        notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityUInt32");
+        return input;
+    }
+
+    @DBus.Description("Returns whatever it is passed")
+    public long IdentityInt64(long input) {
+        done.add("org.freedesktop.DBus.Binding.Tests.IdentityInt64");
+        notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityInt64");
+        return input;
+    }
+
+    @DBus.Description("Returns whatever it is passed")
+    public UInt64 IdentityUInt64(UInt64 input) {
+        done.add("org.freedesktop.DBus.Binding.Tests.IdentityUInt64");
+        notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityUInt64");
+        return input;
+    }
+
+    @DBus.Description("Returns whatever it is passed")
+    public double IdentityDouble(double input) {
+        done.add("org.freedesktop.DBus.Binding.Tests.IdentityDouble");
+        notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityDouble");
+        return input;
+    }
+
+    @DBus.Description("Returns whatever it is passed")
+    public String IdentityString(String input) {
+        done.add("org.freedesktop.DBus.Binding.Tests.IdentityString");
+        notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityString");
+        return input;
+    }
+
+    @DBus.Description("Returns whatever it is passed")
+    public <T> Variant<T>[] IdentityArray(Variant<T>[] input) {
+        done.add("org.freedesktop.DBus.Binding.Tests.IdentityArray");
+        notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityArray");
+        return input;
+    }
+
+    @DBus.Description("Returns whatever it is passed")
+    public byte[] IdentityByteArray(byte[] input) {
+        done.add("org.freedesktop.DBus.Binding.Tests.IdentityByteArray");
+        notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityByteArray");
+        return input;
+    }
+
+    @DBus.Description("Returns whatever it is passed")
+    public boolean[] IdentityBoolArray(boolean[] input) {
+        done.add("org.freedesktop.DBus.Binding.Tests.IdentityBoolArray");
+        notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityBoolArray");
+        return input;
+    }
+
+    @DBus.Description("Returns whatever it is passed")
+    public short[] IdentityInt16Array(short[] input) {
+        done.add("org.freedesktop.DBus.Binding.Tests.IdentityInt16Array");
+        notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityInt16Array");
+        return input;
+    }
+
+    @DBus.Description("Returns whatever it is passed")
+    public UInt16[] IdentityUInt16Array(UInt16[] input) {
+        done.add("org.freedesktop.DBus.Binding.Tests.IdentityUInt16Array");
+        notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityUInt16Array");
+        return input;
+    }
+
+    @DBus.Description("Returns whatever it is passed")
+    public int[] IdentityInt32Array(int[] input) {
+        done.add("org.freedesktop.DBus.Binding.Tests.IdentityInt32Array");
+        notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityInt32Array");
+        return input;
+    }
+
+    @DBus.Description("Returns whatever it is passed")
+    public UInt32[] IdentityUInt32Array(UInt32[] input) {
+        done.add("org.freedesktop.DBus.Binding.Tests.IdentityUInt32Array");
+        notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityUInt32Array");
+        return input;
+    }
+
+    @DBus.Description("Returns whatever it is passed")
+    public long[] IdentityInt64Array(long[] input) {
+        done.add("org.freedesktop.DBus.Binding.Tests.IdentityInt64Array");
+        notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityInt64Array");
+        return input;
+    }
+
+    @DBus.Description("Returns whatever it is passed")
+    public UInt64[] IdentityUInt64Array(UInt64[] input) {
+        done.add("org.freedesktop.DBus.Binding.Tests.IdentityUInt64Array");
+        notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityUInt64Array");
+        return input;
+    }
+
+    @DBus.Description("Returns whatever it is passed")
+    public double[] IdentityDoubleArray(double[] input) {
+        done.add("org.freedesktop.DBus.Binding.Tests.IdentityDoubleArray");
+        notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityDoubleArray");
+        return input;
+    }
+
+    @DBus.Description("Returns whatever it is passed")
+    public String[] IdentityStringArray(String[] input) {
+        done.add("org.freedesktop.DBus.Binding.Tests.IdentityStringArray");
+        notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityStringArray");
+        return input;
+    }
+
+    @DBus.Description("Returns the sum of the values in the input list")
+    public long Sum(int[] a) {
+        done.add("org.freedesktop.DBus.Binding.Tests.Sum");
+        notdone.remove("org.freedesktop.DBus.Binding.Tests.Sum");
+        long sum = 0;
+        for (int b : a) sum += b;
+        return sum;
+    }
+
+    @DBus.Description("Returns the sum of the values in the input list")
+    public UInt32 Sum(byte[] a) {
+        done.add("org.freedesktop.DBus.Binding.SingleTests.Sum");
+        notdone.remove("org.freedesktop.DBus.Binding.SingleTests.Sum");
+        int sum = 0;
+        for (byte b : a) sum += (b < 0 ? b + 256 : b);
+        return new UInt32(sum % (UInt32.MAX_VALUE + 1));
+    }
+
+    @DBus.Description("Given a map of A => B, should return a map of B => a list of all the As which mapped to B")
+    public Map<String, List<String>> InvertMapping(Map<String, String> a) {
+        done.add("org.freedesktop.DBus.Binding.Tests.InvertMapping");
+        notdone.remove("org.freedesktop.DBus.Binding.Tests.InvertMapping");
+        HashMap<String, List<String>> m = new HashMap<String, List<String>>();
+        for (String s : a.keySet()) {
+            String b = a.get(s);
+            List<String> l = m.get(b);
+            if (null == l) {
+                l = new Vector<String>();
+                m.put(b, l);
+            }
+            l.add(s);
+        }
+        return m;
+    }
+
+    @DBus.Description("This method returns the contents of a struct as separate values")
+    public DBus.Binding.Triplet<String, UInt32, Short> DeStruct(DBus.Binding.TestStruct a) {
+        done.add("org.freedesktop.DBus.Binding.Tests.DeStruct");
+        notdone.remove("org.freedesktop.DBus.Binding.Tests.DeStruct");
+        return new DBus.Binding.Triplet<String, UInt32, Short>(a.a, a.b, a.c);
+    }
+
+    @DBus.Description("Given any compound type as a variant, return all the primitive types recursively contained within as an array of variants")
+    @SuppressWarnings("unchecked")
+    public List<Variant<Object>> Primitize(Variant<Object> a) {
+        done.add("org.freedesktop.DBus.Binding.Tests.Primitize");
+        notdone.remove("org.freedesktop.DBus.Binding.Tests.Primitize");
+        return cross_test_client.PrimitizeRecurse(a.getValue(), a.getType());
+    }
+
+    @DBus.Description("inverts it's input")
+    public boolean Invert(boolean a) {
+        done.add("org.freedesktop.DBus.Binding.Tests.Invert");
+        notdone.remove("org.freedesktop.DBus.Binding.Tests.Invert");
+        return !a;
+    }
+
+    @DBus.Description("triggers sending of a signal from the supplied object with the given parameter")
+    public void Trigger(String a, UInt64 b) {
+        done.add("org.freedesktop.DBus.Binding.Tests.Trigger");
+        notdone.remove("org.freedesktop.DBus.Binding.Tests.Trigger");
+        try {
+            conn.sendSignal(new DBus.Binding.TestSignals.Triggered(a, b));
+        } catch (DBusException DBe) {
+            throw new DBusExecutionException(DBe.getMessage());
+        }
+    }
+
+    public void Exit() {
+        done.add("org.freedesktop.DBus.Binding.Tests.Exit");
+        notdone.remove("org.freedesktop.DBus.Binding.Tests.Exit");
+        run = false;
+        synchronized (this) {
+            notifyAll();
+        }
+    }
+
+    public void handle(DBus.Binding.TestClient.Trigger t) {
+        done.add("org.freedesktop.DBus.Binding.TestClient.Trigger");
+        notdone.remove("org.freedesktop.DBus.Binding.TestClient.Trigger");
+        try {
+            DBus.Binding.TestClient cb = conn.getRemoteObject(t.getSource(), "/Test", DBus.Binding.TestClient.class);
+            cb.Response(t.a, t.b);
+        } catch (DBusException DBe) {
+            throw new DBusExecutionException(DBe.getMessage());
+        }
+    }
+
+    public static void main(String[] args) {
+        try {
+            DBusConnection conn = DBusConnection.getConnection(DBusConnection.SESSION);
+            conn.requestBusName("org.freedesktop.DBus.Binding.TestServer");
+            cross_test_server cts = new cross_test_server(conn);
+            conn.addSigHandler(DBus.Binding.TestClient.Trigger.class, cts);
+            conn.exportObject("/Test", cts);
+            synchronized (cts) {
+                while (cts.run) {
+                    try {
+                        cts.wait();
+                    } catch (InterruptedException Ie) {
+                    }
+                }
+            }
+            for (String s : cts.done)
+                System.out.println(s + " ok");
+            for (String s : cts.notdone)
+                System.out.println(s + " untested");
+            conn.disconnect();
+            System.exit(0);
+        } catch (DBusException DBe) {
+            DBe.printStackTrace();
+            System.exit(1);
+        }
+    }
+}
+
                diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/profile.java b/federation/sssd/src/test/java/org/freedesktop/dbus/profile.java
new file mode 100644
index 0000000..e6866a7
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/profile.java
@@ -0,0 +1,378 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.DBus.Introspectable;
+import org.freedesktop.DBus.Peer;
+
+import java.util.HashMap;
+import java.util.Random;
+import java.util.Vector;
+
+class ProfileHandler implements DBusSigHandler<Profiler.ProfileSignal> {
+    public int c = 0;
+
+    public void handle(Profiler.ProfileSignal s) {
+        if (0 == (c++ % profile.SIGNAL_INNER)) System.out.print("-");
+    }
+}
+
+/**
+ * Profiling tests.
+ */
+public class profile {
+    public static final int SIGNAL_INNER = 100;
+    public static final int SIGNAL_OUTER = 100;
+    public static final int PING_INNER = 100;
+    public static final int PING_OUTER = 100;
+    public static final int BYTES = 2000000;
+    public static final int INTROSPECTION_OUTER = 100;
+    public static final int INTROSPECTION_INNER = 10;
+    public static final int STRUCT_OUTER = 100;
+    public static final int STRUCT_INNER = 10;
+    public static final int LIST_OUTER = 100;
+    public static final int LIST_INNER = 10;
+    public static final int LIST_LENGTH = 100;
+    public static final int MAP_OUTER = 100;
+    public static final int MAP_INNER = 10;
+    public static final int MAP_LENGTH = 100;
+    public static final int ARRAY_OUTER = 100;
+    public static final int ARRAY_INNER = 10;
+    public static final int ARRAY_LENGTH = 1000;
+    public static final int STRING_ARRAY_OUTER = 10;
+    public static final int STRING_ARRAY_INNER = 1;
+    public static final int STRING_ARRAY_LENGTH = 20000;
+
+    public static class Log {
+        private long last;
+        private int[] deltas;
+        private int current = 0;
+
+        public Log(int size) {
+            deltas = new int[size];
+        }
+
+        public void start() {
+            last = System.currentTimeMillis();
+        }
+
+        public void stop() {
+            deltas[current] = (int) (System.currentTimeMillis() - last);
+            current++;
+        }
+
+        public double mean() {
+            if (0 == current) return 0;
+            long sum = 0;
+            for (int i = 0; i < current; i++)
+                sum += deltas[i];
+            return sum /= current;
+        }
+
+        public long min() {
+            int m = Integer.MAX_VALUE;
+            for (int i = 0; i < current; i++)
+                if (deltas[i] < m) m = deltas[i];
+            return m;
+        }
+
+        public long max() {
+            int m = 0;
+            for (int i = 0; i < current; i++)
+                if (deltas[i] > m) m = deltas[i];
+            return m;
+        }
+
+        public double stddev() {
+            double mean = mean();
+            double sum = 0;
+            for (int i = 0; i < current; i++)
+                sum += (deltas[i] - mean) * (deltas[i] - mean);
+            return Math.sqrt(sum / (current - 1));
+        }
+    }
+
+    public static void main(String[] args) {
+        try {
+            if (0 == args.length) {
+                System.out.println("You must specify a profile type.");
+                System.out.println("Syntax: profile <pings|arrays|introspect|maps|bytes|lists|structs|signals|rate|strings>");
+                System.exit(1);
+            }
+            DBusConnection conn = DBusConnection.getConnection(DBusConnection.SESSION);
+            conn.requestBusName("org.freedesktop.DBus.java.profiler");
+            if ("pings".equals(args[0])) {
+                int count = PING_INNER * PING_OUTER;
+                System.out.print("Sending " + count + " pings...");
+                Peer p = conn.getRemoteObject("org.freedesktop.DBus.java.profiler", "/Profiler", Peer.class);
+                Log l = new Log(count);
+                long t = System.currentTimeMillis();
+                for (int i = 0; i < PING_OUTER; i++) {
+                    for (int j = 0; j < PING_INNER; j++) {
+                        l.start();
+                        p.Ping();
+                        l.stop();
+                    }
+                    System.out.print("");
+                }
+                t = System.currentTimeMillis() - t;
+                System.out.println(" done.");
+                System.out.println("min/max/avg (ms): " + l.min() + "/" + l.max() + "/" + l.mean());
+                System.out.println("deviation: " + l.stddev());
+                System.out.println("Total time: " + t + "ms");
+            } else if ("strings".equals(args[0])) {
+                int count = STRING_ARRAY_INNER * STRING_ARRAY_OUTER;
+                System.out.print("Sending array of " + STRING_ARRAY_LENGTH + " strings " + count + " times.");
+                ProfilerInstance pi = new ProfilerInstance();
+                conn.exportObject("/Profiler", pi);
+                Profiler p = conn.getRemoteObject("org.freedesktop.DBus.java.profiler", "/Profiler", Profiler.class);
+                String[] v = new String[STRING_ARRAY_LENGTH];
+                Random r = new Random();
+                for (int i = 0; i < STRING_ARRAY_LENGTH; i++) v[i] = "" + r.nextInt();
+                Log l = new Log(count);
+                long t = System.currentTimeMillis();
+                for (int i = 0; i < STRING_ARRAY_OUTER; i++) {
+                    for (int j = 0; j < STRING_ARRAY_INNER; j++) {
+                        l.start();
+                        p.stringarray(v);
+                        l.stop();
+                    }
+                    System.out.print("");
+                }
+                t = System.currentTimeMillis() - t;
+                System.out.println(" done.");
+                System.out.println("min/max/avg (ms): " + l.min() + "/" + l.max() + "/" + l.mean());
+                System.out.println("deviation: " + l.stddev());
+                System.out.println("Total time: " + t + "ms");
+            } else if ("arrays".equals(args[0])) {
+                int count = ARRAY_INNER * ARRAY_OUTER;
+                System.out.print("Sending array of " + ARRAY_LENGTH + " ints " + count + " times.");
+                ProfilerInstance pi = new ProfilerInstance();
+                conn.exportObject("/Profiler", pi);
+                Profiler p = conn.getRemoteObject("org.freedesktop.DBus.java.profiler", "/Profiler", Profiler.class);
+                int[] v = new int[ARRAY_LENGTH];
+                Random r = new Random();
+                for (int i = 0; i < ARRAY_LENGTH; i++) v[i] = r.nextInt();
+                Log l = new Log(count);
+                long t = System.currentTimeMillis();
+                for (int i = 0; i < ARRAY_OUTER; i++) {
+                    for (int j = 0; j < ARRAY_INNER; j++) {
+                        l.start();
+                        p.array(v);
+                        l.stop();
+                    }
+                    System.out.print("");
+                }
+                t = System.currentTimeMillis() - t;
+                System.out.println(" done.");
+                System.out.println("min/max/avg (ms): " + l.min() + "/" + l.max() + "/" + l.mean());
+                System.out.println("deviation: " + l.stddev());
+                System.out.println("Total time: " + t + "ms");
+            } else if ("maps".equals(args[0])) {
+                int count = MAP_INNER * MAP_OUTER;
+                System.out.print("Sending map of " + MAP_LENGTH + " string=>strings " + count + " times.");
+                ProfilerInstance pi = new ProfilerInstance();
+                conn.exportObject("/Profiler", pi);
+                Profiler p = conn.getRemoteObject("org.freedesktop.DBus.java.profiler", "/Profiler", Profiler.class);
+                HashMap<String, String> m = new HashMap<String, String>();
+                for (int i = 0; i < MAP_LENGTH; i++)
+                    m.put("" + i, "hello");
+                Log l = new Log(count);
+                long t = System.currentTimeMillis();
+                for (int i = 0; i < MAP_OUTER; i++) {
+                    for (int j = 0; j < MAP_INNER; j++) {
+                        l.start();
+                        p.map(m);
+                        l.stop();
+                    }
+                    System.out.print("");
+                }
+                t = System.currentTimeMillis() - t;
+                System.out.println(" done.");
+                System.out.println("min/max/avg (ms): " + l.min() + "/" + l.max() + "/" + l.mean());
+                System.out.println("deviation: " + l.stddev());
+                System.out.println("Total time: " + t + "ms");
+            } else if ("lists".equals(args[0])) {
+                int count = LIST_OUTER * LIST_INNER;
+                System.out.print("Sending list of " + LIST_LENGTH + " strings " + count + " times.");
+                ProfilerInstance pi = new ProfilerInstance();
+                conn.exportObject("/Profiler", pi);
+                Profiler p = conn.getRemoteObject("org.freedesktop.DBus.java.profiler", "/Profiler", Profiler.class);
+                Vector<String> v = new Vector<String>();
+                for (int i = 0; i < LIST_LENGTH; i++)
+                    v.add("hello " + i);
+                Log l = new Log(count);
+                long t = System.currentTimeMillis();
+                for (int i = 0; i < LIST_OUTER; i++) {
+                    for (int j = 0; j < LIST_INNER; j++) {
+                        l.start();
+                        p.list(v);
+                        l.stop();
+                    }
+                    System.out.print("");
+                }
+                t = System.currentTimeMillis() - t;
+                System.out.println(" done.");
+                System.out.println("min/max/avg (ms): " + l.min() + "/" + l.max() + "/" + l.mean());
+                System.out.println("deviation: " + l.stddev());
+                System.out.println("Total time: " + t + "ms");
+            } else if ("structs".equals(args[0])) {
+                int count = STRUCT_OUTER * STRUCT_INNER;
+                System.out.print("Sending a struct " + count + " times.");
+                ProfilerInstance pi = new ProfilerInstance();
+                conn.exportObject("/Profiler", pi);
+                Profiler p = conn.getRemoteObject("org.freedesktop.DBus.java.profiler", "/Profiler", Profiler.class);
+                ProfileStruct ps = new ProfileStruct("hello", new UInt32(18), 500L);
+                Log l = new Log(count);
+                long t = System.currentTimeMillis();
+                for (int i = 0; i < STRUCT_OUTER; i++) {
+                    for (int j = 0; j < STRUCT_INNER; j++) {
+                        l.start();
+                        p.struct(ps);
+                        l.stop();
+                    }
+                    System.out.print("");
+                }
+                t = System.currentTimeMillis() - t;
+                System.out.println(" done.");
+                System.out.println("min/max/avg (ms): " + l.min() + "/" + l.max() + "/" + l.mean());
+                System.out.println("deviation: " + l.stddev());
+                System.out.println("Total time: " + t + "ms");
+            } else if ("introspect".equals(args[0])) {
+                int count = INTROSPECTION_OUTER * INTROSPECTION_INNER;
+                System.out.print("Recieving introspection data " + count + " times.");
+                ProfilerInstance pi = new ProfilerInstance();
+                conn.exportObject("/Profiler", pi);
+                Introspectable is = conn.getRemoteObject("org.freedesktop.DBus.java.profiler", "/Profiler", Introspectable.class);
+                Log l = new Log(count);
+                long t = System.currentTimeMillis();
+                String s = null;
+                for (int i = 0; i < INTROSPECTION_OUTER; i++) {
+                    for (int j = 0; j < INTROSPECTION_INNER; j++) {
+                        l.start();
+                        s = is.Introspect();
+                        l.stop();
+                    }
+                    System.out.print("");
+                }
+                t = System.currentTimeMillis() - t;
+                System.out.println(" done.");
+                System.out.println("min/max/avg (ms): " + l.min() + "/" + l.max() + "/" + l.mean());
+                System.out.println("deviation: " + l.stddev());
+                System.out.println("Total time: " + t + "ms");
+                System.out.println("Introspect data: " + s);
+            } else if ("bytes".equals(args[0])) {
+                System.out.print("Sending " + BYTES + " bytes");
+                ProfilerInstance pi = new ProfilerInstance();
+                conn.exportObject("/Profiler", pi);
+                Profiler p = conn.getRemoteObject("org.freedesktop.DBus.java.profiler", "/Profiler", Profiler.class);
+                byte[] bs = new byte[BYTES];
+                for (int i = 0; i < BYTES; i++)
+                    bs[i] = (byte) i;
+                long t = System.currentTimeMillis();
+                p.bytes(bs);
+                System.out.println(" done in " + (System.currentTimeMillis() - t) + "ms.");
+            } else if ("rate".equals(args[0])) {
+                ProfilerInstance pi = new ProfilerInstance();
+                conn.exportObject("/Profiler", pi);
+                Profiler p = conn.getRemoteObject("org.freedesktop.DBus.java.profiler", "/Profiler", Profiler.class);
+                Peer peer = conn.getRemoteObject("org.freedesktop.DBus.java.profiler", "/Profiler", Peer.class);
+                conn.changeThreadCount((byte) 1);
+
+                long start = System.currentTimeMillis();
+                int count = 0;
+                do {
+                    p.Pong();
+                    count++;
+                } while (count < 10000);
+                long end = System.currentTimeMillis();
+                System.out.println("No payload: " + ((count * 1000) / (end - start)) + " RT/second");
+                start = System.currentTimeMillis();
+                count = 0;
+                do {
+                    p.Pong();
+                    count++;
+                } while (count < 10000);
+                peer.Ping();
+                end = System.currentTimeMillis();
+                System.out.println("No payload, One way: " + ((count * 1000) / (end - start)) + " /second");
+                int len = 256;
+                while (len <= 32768) {
+                    byte[] bs = new byte[len];
+                    count = 0;
+                    start = System.currentTimeMillis();
+                    do {
+                        p.bytes(bs);
+                        count++;
+                    } while (count < 1000);
+                    end = System.currentTimeMillis();
+                    long ms = end - start;
+                    double cps = (count * 1000) / ms;
+                    double rate = (len * cps) / (1024.0 * 1024.0);
+                    System.out.println(len + " byte array) " + (count * len) + " bytes in " + ms + "ms (in " + count + " calls / " + (int) cps + " CPS): " + rate + "MB/s");
+                    len <<= 1;
+                }
+                len = 256;
+                while (len <= 32768) {
+                    StringBuilder sb = new StringBuilder();
+                    for (int i = 0; i < len; i++) sb.append('a');
+                    String s = sb.toString();
+                    end = System.currentTimeMillis() + 500;
+                    count = 0;
+                    do {
+                        p.string(s);
+                        count++;
+                    } while (count < 1000);
+                    long ms = end - start;
+                    double cps = (count * 1000) / ms;
+                    double rate = (len * cps) / (1024.0 * 1024.0);
+                    System.out.println(len + " string) " + (count * len) + " bytes in " + ms + "ms (in " + count + " calls / " + (int) cps + " CPS): " + rate + "MB/s");
+                    len <<= 1;
+                }
+            } else if ("signals".equals(args[0])) {
+                int count = SIGNAL_OUTER * SIGNAL_INNER;
+                System.out.print("Sending " + count + " signals");
+                ProfileHandler ph = new ProfileHandler();
+                conn.addSigHandler(Profiler.ProfileSignal.class, ph);
+                Log l = new Log(count);
+                Profiler.ProfileSignal ps = new Profiler.ProfileSignal("/");
+                long t = System.currentTimeMillis();
+                for (int i = 0; i < SIGNAL_OUTER; i++) {
+                    for (int j = 0; j < SIGNAL_INNER; j++) {
+                        l.start();
+                        conn.sendSignal(ps);
+                        l.stop();
+                    }
+                    System.out.print("");
+                }
+                t = System.currentTimeMillis() - t;
+                System.out.println(" done.");
+                System.out.println("min/max/avg (ms): " + l.min() + "/" + l.max() + "/" + l.mean());
+                System.out.println("deviation: " + l.stddev());
+                System.out.println("Total time: " + t + "ms");
+                while (ph.c < count) try {
+                    Thread.sleep(100);
+                } catch (InterruptedException Ie) {
+                }
+                ;
+            } else {
+                conn.disconnect();
+                System.out.println("Invalid profile ``" + args[0] + "''.");
+                System.out.println("Syntax: profile <pings|arrays|introspect|maps|bytes|lists|structs|signals>");
+                System.exit(1);
+            }
+            conn.disconnect();
+        } catch (Exception e) {
+            e.printStackTrace();
+            System.exit(1);
+        }
+    }
+}
                diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/Profiler.java b/federation/sssd/src/test/java/org/freedesktop/dbus/Profiler.java
new file mode 100644
index 0000000..cd549d5
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/Profiler.java
@@ -0,0 +1,44 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.dbus.exceptions.DBusException;
+
+import java.util.List;
+import java.util.Map;
+
+public interface Profiler extends DBusInterface {
+    public class ProfileSignal extends DBusSignal {
+        public ProfileSignal(String path) throws DBusException {
+            super(path);
+        }
+    }
+
+    public void array(int[] v);
+
+    public void stringarray(String[] v);
+
+    public void map(Map<String, String> m);
+
+    public void list(List<String> l);
+
+    public void bytes(byte[] b);
+
+    public void struct(ProfileStruct ps);
+
+    public void string(String s);
+
+    public void NoReply();
+
+    public void Pong();
+}
+
+
                diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/ProfilerInstance.java b/federation/sssd/src/test/java/org/freedesktop/dbus/ProfilerInstance.java
new file mode 100644
index 0000000..530901f
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/ProfilerInstance.java
@@ -0,0 +1,56 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import java.util.List;
+import java.util.Map;
+
+public class ProfilerInstance implements Profiler {
+    public boolean isRemote() {
+        return false;
+    }
+
+    public void array(int[] v) {
+        return;
+    }
+
+    public void stringarray(String[] v) {
+        return;
+    }
+
+    public void map(Map<String, String> m) {
+        return;
+    }
+
+    public void list(List<String> l) {
+        return;
+    }
+
+    public void bytes(byte[] b) {
+        return;
+    }
+
+    public void struct(ProfileStruct ps) {
+        return;
+    }
+
+    public void string(String s) {
+        return;
+    }
+
+    public void NoReply() {
+        return;
+    }
+
+    public void Pong() {
+        return;
+    }
+}
                diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/ProfileStruct.java b/federation/sssd/src/test/java/org/freedesktop/dbus/ProfileStruct.java
new file mode 100644
index 0000000..b86c137
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/ProfileStruct.java
@@ -0,0 +1,26 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+public final class ProfileStruct extends Struct {
+    @Position(0)
+    public final String a;
+    @Position(1)
+    public final UInt32 b;
+    @Position(2)
+    public final long c;
+
+    public ProfileStruct(String a, UInt32 b, long c) {
+        this.a = a;
+        this.b = b;
+        this.c = c;
+    }
+}
                diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/test.java b/federation/sssd/src/test/java/org/freedesktop/dbus/test.java
new file mode 100644
index 0000000..af6a736
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/test.java
@@ -0,0 +1,991 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.DBus;
+import org.freedesktop.DBus.Error.MatchRuleInvalid;
+import org.freedesktop.DBus.Error.ServiceUnknown;
+import org.freedesktop.DBus.Error.UnknownObject;
+import org.freedesktop.DBus.Introspectable;
+import org.freedesktop.DBus.Peer;
+import org.freedesktop.DBus.Properties;
+import org.freedesktop.dbus.exceptions.DBusException;
+import org.freedesktop.dbus.exceptions.DBusExecutionException;
+import org.freedesktop.dbus.exceptions.NotConnected;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.text.Collator;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Vector;
+
+class testnewclass implements TestNewInterface {
+    public boolean isRemote() {
+        return false;
+    }
+
+    public String getName() {
+        return toString();
+    }
+}
+
+class testclass implements TestRemoteInterface, TestRemoteInterface2, TestSignalInterface, TestSignalInterface2, Properties {
+    private DBusConnection conn;
+
+    public testclass(DBusConnection conn) {
+        this.conn = conn;
+    }
+
+    public String Introspect() {
+        return "Not XML";
+    }
+
+    public int[][] teststructstruct(TestStruct3 in) {
+        List<List<Integer>> lli = in.b;
+        int[][] out = new int[lli.size()][];
+        for (int j = 0; j < out.length; j++) {
+            out[j] = new int[lli.get(j).size()];
+            for (int k = 0; k < out[j].length; k++)
+                out[j][k] = lli.get(j).get(k);
+        }
+        return out;
+    }
+
+    public float testfloat(float[] f) {
+        if (f.length < 4 ||
+                f[0] != 17.093f ||
+                f[1] != -23f ||
+                f[2] != 0.0f ||
+                f[3] != 31.42f)
+            test.fail("testfloat got incorrect array");
+        return f[0];
+    }
+
+    public void newpathtest(Path p) {
+        if (!p.toString().equals("/new/path/test"))
+            test.fail("new path test got wrong path");
+    }
+
+    public void waitawhile() {
+        System.out.println("Sleeping.");
+        try {
+            Thread.sleep(1000);
+        } catch (InterruptedException Ie) {
+        }
+        System.out.println("Done sleeping.");
+    }
+
+    public <A> TestTuple<String, List<Integer>, Boolean> show(A in) {
+        System.out.println("Showing Stuff: " + in.getClass() + "(" + in + ")");
+        if (!(in instanceof Integer) || ((Integer) in).intValue() != 234)
+            test.fail("show received the wrong arguments");
+        DBusCallInfo info = DBusConnection.getCallInfo();
+        List<Integer> l = new Vector<Integer>();
+        l.add(1953);
+        return new TestTuple<String, List<Integer>, Boolean>(info.getSource(), l, true);
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T> T dostuff(TestStruct foo) {
+        System.out.println("Doing Stuff " + foo);
+        System.out.println(" -- (" + foo.a.getClass() + ", " + foo.b.getClass() + ", " + foo.c.getClass() + ")");
+        if (!(foo instanceof TestStruct) ||
+                !(foo.a instanceof String) ||
+                !(foo.b instanceof UInt32) ||
+                !(foo.c instanceof Variant) ||
+                !"bar".equals(foo.a) ||
+                foo.b.intValue() != 52 ||
+                !(foo.c.getValue() instanceof Boolean) ||
+                ((Boolean) foo.c.getValue()).booleanValue() != true)
+            test.fail("dostuff received the wrong arguments");
+        return (T) foo.c.getValue();
+    }
+
+    /**
+     * Local classes MUST implement this to return false
+     */
+    public boolean isRemote() {
+        return false;
+    }
+
+    /**
+     * The method we are exporting to the Bus.
+     */
+    public List<Integer> sampleArray(List<String> ss, Integer[] is, long[] ls) {
+        System.out.println("Got an array:");
+        for (String s : ss)
+            System.out.println("--" + s);
+        if (ss.size() != 5 ||
+                !"hi".equals(ss.get(0)) ||
+                !"hello".equals(ss.get(1)) ||
+                !"hej".equals(ss.get(2)) ||
+                !"hey".equals(ss.get(3)) ||
+                !"aloha".equals(ss.get(4)))
+            test.fail("sampleArray, String array contents incorrect");
+        System.out.println("Got an array:");
+        for (Integer i : is)
+            System.out.println("--" + i);
+        if (is.length != 4 ||
+                is[0].intValue() != 1 ||
+                is[1].intValue() != 5 ||
+                is[2].intValue() != 7 ||
+                is[3].intValue() != 9)
+            test.fail("sampleArray, Integer array contents incorrect");
+        System.out.println("Got an array:");
+        for (long l : ls)
+            System.out.println("--" + l);
+        if (ls.length != 4 ||
+                ls[0] != 2 ||
+                ls[1] != 6 ||
+                ls[2] != 8 ||
+                ls[3] != 12)
+            test.fail("sampleArray, Integer array contents incorrect");
+        Vector<Integer> v = new Vector<Integer>();
+        v.add(-1);
+        v.add(-5);
+        v.add(-7);
+        v.add(-12);
+        v.add(-18);
+        return v;
+    }
+
+    public String getName() {
+        return "This Is A UTF-8 Name: س !!";
+    }
+
+    public String getNameAndThrow() throws TestException {
+        throw new TestException("test");
+    }
+
+    public boolean check() {
+        System.out.println("Being checked");
+        return false;
+    }
+
+    public <T> int frobnicate(List<Long> n, Map<String, Map<UInt16, Short>> m, T v) {
+        if (null == n)
+            test.fail("List was null");
+        if (n.size() != 3)
+            test.fail("List was wrong size (expected 3, actual " + n.size() + ")");
+        if (n.get(0) != 2L ||
+                n.get(1) != 5L ||
+                n.get(2) != 71L)
+            test.fail("List has wrong contents");
+        if (!(v instanceof Integer))
+            test.fail("v not an Integer");
+        if (((Integer) v) != 13)
+            test.fail("v is incorrect");
+        if (null == m)
+            test.fail("Map was null");
+        if (m.size() != 1)
+            test.fail("Map was wrong size");
+        if (!m.keySet().contains("stuff"))
+            test.fail("Incorrect key");
+        Map<UInt16, Short> mus = m.get("stuff");
+        if (null == mus)
+            test.fail("Sub-Map was null");
+        if (mus.size() != 3)
+            test.fail("Sub-Map was wrong size");
+        if (!(new Short((short) 5).equals(mus.get(new UInt16(4)))))
+            test.fail("Sub-Map has wrong contents");
+        if (!(new Short((short) 6).equals(mus.get(new UInt16(5)))))
+            test.fail("Sub-Map has wrong contents");
+        if (!(new Short((short) 7).equals(mus.get(new UInt16(6)))))
+            test.fail("Sub-Map has wrong contents");
+        return -5;
+    }
+
+    public DBusInterface getThis(DBusInterface t) {
+        if (!t.equals(this))
+            test.fail("Didn't get this properly");
+        return this;
+    }
+
+    public void throwme() throws TestException {
+        throw new TestException("test");
+    }
+
+    public TestSerializable<String> testSerializable(byte b, TestSerializable<String> s, int i) {
+        System.out.println("Recieving TestSerializable: " + s);
+        if (b != 12
+                || i != 13
+                || !(s.getInt() == 1)
+                || !(s.getString().equals("woo"))
+                || !(s.getVector().size() == 3)
+                || !(s.getVector().get(0) == 1)
+                || !(s.getVector().get(1) == 2)
+                || !(s.getVector().get(2) == 3))
+            test.fail("Error in recieving custom synchronisation");
+        return s;
+    }
+
+    public String recursionTest() {
+        try {
+            TestRemoteInterface tri = conn.getRemoteObject("foo.bar.Test", "/Test", TestRemoteInterface.class);
+            return tri.getName();
+        } catch (DBusException DBe) {
+            test.fail("Failed with error: " + DBe);
+            return "";
+        }
+    }
+
+    public int overload(String s) {
+        return 1;
+    }
+
+    public int overload(byte b) {
+        return 2;
+    }
+
+    public int overload() {
+        DBusCallInfo info = DBusConnection.getCallInfo();
+        if ("org.freedesktop.dbus.test.AlternateTestInterface".equals(info.getInterface()))
+            return 3;
+        else if ("org.freedesktop.dbus.test.TestRemoteInterface".equals(info.getInterface()))
+            return 4;
+        else
+            return -1;
+    }
+
+    public List<List<Integer>> checklist(List<List<Integer>> lli) {
+        return lli;
+    }
+
+    public TestNewInterface getNew() {
+        testnewclass n = new testnewclass();
+        try {
+            conn.exportObject("/new", n);
+        } catch (DBusException DBe) {
+            throw new DBusExecutionException(DBe.getMessage());
+        }
+        return n;
+    }
+
+    public void sig(Type[] s) {
+        if (s.length != 2
+                || !s[0].equals(Byte.class)
+                || !(s[1] instanceof ParameterizedType)
+                || !Map.class.equals(((ParameterizedType) s[1]).getRawType())
+                || ((ParameterizedType) s[1]).getActualTypeArguments().length != 2
+                || !String.class.equals(((ParameterizedType) s[1]).getActualTypeArguments()[0])
+                || !Integer.class.equals(((ParameterizedType) s[1]).getActualTypeArguments()[1]))
+            test.fail("Didn't send types correctly");
+    }
+
+    @SuppressWarnings("unchecked")
+    public void complexv(Variant<? extends Object> v) {
+        if (!"a{ss}".equals(v.getSig())
+                || !(v.getValue() instanceof Map)
+                || ((Map<Object, Object>) v.getValue()).size() != 1
+                || !"moo".equals(((Map<Object, Object>) v.getValue()).get("cow")))
+            test.fail("Didn't send variant correctly");
+    }
+
+    public void reg13291(byte[] as, byte[] bs) {
+        if (as.length != bs.length) test.fail("didn't receive identical byte arrays");
+        for (int i = 0; i < as.length; i++)
+            if (as[i] != bs[i]) test.fail("didn't receive identical byte arrays");
+    }
+
+    @SuppressWarnings("unchecked")
+    public <A> A Get(String interface_name, String property_name) {
+        return (A) new Path("/nonexistant/path");
+    }
+
+    public <A> void Set(String interface_name, String property_name, A value) {
+    }
+
+    public Map<String, Variant> GetAll(String interface_name) {
+        return new HashMap<String, Variant>();
+    }
+
+    public Path pathrv(Path a) {
+        return a;
+    }
+
+    public List<Path> pathlistrv(List<Path> a) {
+        return a;
+    }
+
+    public Map<Path, Path> pathmaprv(Map<Path, Path> a) {
+        return a;
+    }
+
+    @SuppressWarnings("unchecked")
+    public Map<String, Variant> svm() {
+        HashMap<String, Variant> properties = new HashMap<String, Variant>();
+        HashMap<String, Variant<String>> parameters = new HashMap<String, Variant<String>>();
+
+        parameters.put("Name", new Variant<String>("Joe"));
+        parameters.put("Password", new Variant<String>("abcdef"));
+
+        properties.put("Parameters", new Variant(parameters, "a{sv}"));
+        return (Map<String, Variant>) properties;
+    }
+}
+
+/**
+ * Typed signal handler for renamed signal
+ */
+class renamedsignalhandler implements DBusSigHandler<TestSignalInterface2.TestRenamedSignal> {
+    /**
+     * Handling a signal
+     */
+    public void handle(TestSignalInterface2.TestRenamedSignal t) {
+        if (false == test.done5) {
+            test.done5 = true;
+        } else {
+            test.fail("SignalHandler R has been run too many times");
+        }
+        System.out.println("SignalHandler R Running");
+        System.out.println("string(" + t.value + ") int(" + t.number + ")");
+        if (!"Bar".equals(t.value) || !(new UInt32(42)).equals(t.number))
+            test.fail("Incorrect TestRenamedSignal parameters");
+    }
+}
+
+/**
+ * Empty signal handler
+ */
+class emptysignalhandler implements DBusSigHandler<TestSignalInterface.EmptySignal> {
+    /**
+     * Handling a signal
+     */
+    public void handle(TestSignalInterface.EmptySignal t) {
+        if (false == test.done7) {
+            test.done7 = true;
+        } else {
+            test.fail("SignalHandler E has been run too many times");
+        }
+        System.out.println("SignalHandler E Running");
+    }
+}
+
+/**
+ * Disconnect handler
+ */
+class disconnecthandler implements DBusSigHandler<DBus.Local.Disconnected> {
+    private DBusConnection conn;
+    private renamedsignalhandler sh;
+
+    public disconnecthandler(DBusConnection conn, renamedsignalhandler sh) {
+        this.conn = conn;
+        this.sh = sh;
+    }
+
+    /**
+     * Handling a signal
+     */
+    public void handle(DBus.Local.Disconnected t) {
+        if (false == test.done6) {
+            test.done6 = true;
+            System.out.println("Handling disconnect, unregistering handler");
+            try {
+                conn.removeSigHandler(TestSignalInterface2.TestRenamedSignal.class, sh);
+            } catch (DBusException DBe) {
+                DBe.printStackTrace();
+                test.fail("Disconnect handler threw an exception: " + DBe);
+            }
+        }
+    }
+}
+
+
+/**
+ * Typed signal handler
+ */
+class pathsignalhandler implements DBusSigHandler<TestSignalInterface.TestPathSignal> {
+    /**
+     * Handling a signal
+     */
+    public void handle(TestSignalInterface.TestPathSignal t) {
+        System.out.println("Path sighandler: " + t);
+    }
+}
+
+/**
+ * Typed signal handler
+ */
+class signalhandler implements DBusSigHandler<TestSignalInterface.TestSignal> {
+    /**
+     * Handling a signal
+     */
+    public void handle(TestSignalInterface.TestSignal t) {
+        if (false == test.done1) {
+            test.done1 = true;
+        } else {
+            test.fail("SignalHandler 1 has been run too many times");
+        }
+        System.out.println("SignalHandler 1 Running");
+        System.out.println("string(" + t.value + ") int(" + t.number + ")");
+        if (!"Bar".equals(t.value) || !(new UInt32(42)).equals(t.number))
+            test.fail("Incorrect TestSignal parameters");
+    }
+}
+
+/**
+ * Untyped signal handler
+ */
+class arraysignalhandler implements DBusSigHandler<TestSignalInterface.TestArraySignal> {
+    /**
+     * Handling a signal
+     */
+    public void handle(TestSignalInterface.TestArraySignal t) {
+        try {
+            if (false == test.done2) {
+                test.done2 = true;
+            } else {
+                test.fail("SignalHandler 2 has been run too many times");
+            }
+            System.out.println("SignalHandler 2 Running");
+            if (t.v.size() != 1)
+                test.fail("Incorrect TestArraySignal array length: should be 1, actually " + t.v.size());
+            System.out.println("Got a test array signal with Parameters: ");
+            for (String str : t.v.get(0).a)
+                System.out.println("--" + str);
+            System.out.println(t.v.get(0).b.getType());
+            System.out.println(t.v.get(0).b.getValue());
+            if (!(t.v.get(0).b.getValue() instanceof UInt64) ||
+                    567L != ((UInt64) t.v.get(0).b.getValue()).longValue() ||
+                    t.v.get(0).a.size() != 5 ||
+                    !"hi".equals(t.v.get(0).a.get(0)) ||
+                    !"hello".equals(t.v.get(0).a.get(1)) ||
+                    !"hej".equals(t.v.get(0).a.get(2)) ||
+                    !"hey".equals(t.v.get(0).a.get(3)) ||
+                    !"aloha".equals(t.v.get(0).a.get(4)))
+                test.fail("Incorrect TestArraySignal parameters");
+
+            if (t.m.keySet().size() != 2)
+                test.fail("Incorrect TestArraySignal map size: should be 2, actually " + t.m.keySet().size());
+            if (!(t.m.get(new UInt32(1)).b.getValue() instanceof UInt64) ||
+                    678L != ((UInt64) t.m.get(new UInt32(1)).b.getValue()).longValue() ||
+                    !(t.m.get(new UInt32(42)).b.getValue() instanceof UInt64) ||
+                    789L != ((UInt64) t.m.get(new UInt32(42)).b.getValue()).longValue())
+                test.fail("Incorrect TestArraySignal parameters");
+
+        } catch (Exception e) {
+            e.printStackTrace();
+            test.fail("SignalHandler 2 threw an exception: " + e);
+        }
+    }
+}
+
+/**
+ * Object path signal handler
+ */
+class objectsignalhandler implements DBusSigHandler<TestSignalInterface.TestObjectSignal> {
+    public void handle(TestSignalInterface.TestObjectSignal s) {
+        if (false == test.done3) {
+            test.done3 = true;
+        } else {
+            test.fail("SignalHandler 3 has been run too many times");
+        }
+        System.out.println(s.otherpath);
+    }
+}
+
+/**
+ * handler which should never be called
+ */
+class badarraysignalhandler<T extends DBusSignal> implements DBusSigHandler<T> {
+    /**
+     * Handling a signal
+     */
+    public void handle(T s) {
+        test.fail("This signal handler shouldn't be called");
+    }
+}
+
+/**
+ * Callback handler
+ */
+class callbackhandler implements CallbackHandler<String> {
+    public void handle(String r) {
+        System.out.println("Handling callback: " + r);
+        Collator col = Collator.getInstance();
+        col.setDecomposition(Collator.FULL_DECOMPOSITION);
+        col.setStrength(Collator.PRIMARY);
+        if (0 != col.compare("This Is A UTF-8 Name: ﺱ !!", r))
+            test.fail("call with callback, wrong return value");
+        if (test.done4) test.fail("Already ran callback handler");
+        test.done4 = true;
+    }
+
+    public void handleError(DBusExecutionException e) {
+        System.out.println("Handling error callback: " + e + " message = '" + e.getMessage() + "'");
+        if (!(e instanceof TestException)) test.fail("Exception is of the wrong sort");
+        Collator col = Collator.getInstance();
+        col.setDecomposition(Collator.FULL_DECOMPOSITION);
+        col.setStrength(Collator.PRIMARY);
+        if (0 != col.compare("test", e.getMessage()))
+            test.fail("Exception has the wrong message");
+        if (test.done8) test.fail("Already ran callback error handler");
+        test.done8 = true;
+    }
+}
+
+/**
+ * This is a test program which sends and recieves a signal, implements, exports and calls a remote method.
+ */
+public class test {
+    public static boolean done1 = false;
+    public static boolean done2 = false;
+    public static boolean done3 = false;
+    public static boolean done4 = false;
+    public static boolean done5 = false;
+    public static boolean done6 = false;
+    public static boolean done7 = false;
+    public static boolean done8 = false;
+
+    public static void fail(String message) {
+        System.out.println("Test Failed: " + message);
+        System.err.println("Test Failed: " + message);
+        if (null != serverconn) serverconn.disconnect();
+        if (null != clientconn) clientconn.disconnect();
+        System.exit(1);
+    }
+
+    static DBusConnection serverconn = null;
+    static DBusConnection clientconn = null;
+
+    @SuppressWarnings("unchecked")
+    public static void main(String[] args) {
+        try {
+            System.out.println("Creating Connection");
+            serverconn = DBusConnection.getConnection(DBusConnection.SESSION);
+            clientconn = DBusConnection.getConnection(DBusConnection.SESSION);
+            serverconn.setWeakReferences(true);
+            clientconn.setWeakReferences(true);
+
+            System.out.println("Registering Name");
+            serverconn.requestBusName("foo.bar.Test");
+
+            /** This gets a remote object matching our bus name and exported object path. */
+            Peer peer = clientconn.getRemoteObject("foo.bar.Test", "/Test", Peer.class);
+            DBus dbus = clientconn.getRemoteObject("org.freedesktop.DBus", "/org/freedesktop/DBus", DBus.class);
+
+            System.out.print("Listening for signals...");
+            signalhandler sigh = new signalhandler();
+            renamedsignalhandler rsh = new renamedsignalhandler();
+            try {
+                /** This registers an instance of the test class as the signal handler for the TestSignal class. */
+                clientconn.addSigHandler(TestSignalInterface.EmptySignal.class, new emptysignalhandler());
+                clientconn.addSigHandler(TestSignalInterface.TestSignal.class, sigh);
+                clientconn.addSigHandler(TestSignalInterface2.TestRenamedSignal.class, rsh);
+                clientconn.addSigHandler(DBus.Local.Disconnected.class, new disconnecthandler(clientconn, rsh));
+                String source = dbus.GetNameOwner("foo.bar.Test");
+                clientconn.addSigHandler(TestSignalInterface.TestArraySignal.class, source, peer, new arraysignalhandler());
+                clientconn.addSigHandler(TestSignalInterface.TestObjectSignal.class, new objectsignalhandler());
+                clientconn.addSigHandler(TestSignalInterface.TestPathSignal.class, new pathsignalhandler());
+                badarraysignalhandler<TestSignalInterface.TestSignal> bash = new badarraysignalhandler<TestSignalInterface.TestSignal>();
+                clientconn.addSigHandler(TestSignalInterface.TestSignal.class, bash);
+                clientconn.removeSigHandler(TestSignalInterface.TestSignal.class, bash);
+                System.out.println("done");
+            } catch (MatchRuleInvalid MRI) {
+                test.fail("Failed to add handlers: " + MRI.getMessage());
+            } catch (DBusException DBe) {
+                test.fail("Failed to add handlers: " + DBe.getMessage());
+            }
+
+            System.out.println("Listening for Method Calls");
+            testclass tclass = new testclass(serverconn);
+            testclass tclass2 = new testclass(serverconn);
+            /** This exports an instance of the test class as the object /Test. */
+            serverconn.exportObject("/Test", tclass);
+            serverconn.exportObject("/BadTest", tclass);
+            serverconn.exportObject("/BadTest2", tclass2);
+            serverconn.addFallback("/FallbackTest", tclass);
+
+            // explicitly unexport object
+            serverconn.unExportObject("/BadTest");
+            // implicitly unexport object
+            tclass2 = null;
+            System.gc();
+            System.runFinalization();
+            System.gc();
+            System.runFinalization();
+            System.gc();
+            System.runFinalization();
+
+            System.out.println("Sending Signal");
+            /** This creates an instance of the Test Signal, with the given object path, signal name and parameters, and broadcasts in on the Bus. */
+            serverconn.sendSignal(new TestSignalInterface.TestSignal("/foo/bar/Wibble", "Bar", new UInt32(42)));
+            serverconn.sendSignal(new TestSignalInterface.EmptySignal("/foo/bar/Wibble"));
+            serverconn.sendSignal(new TestSignalInterface2.TestRenamedSignal("/foo/bar/Wibble", "Bar", new UInt32(42)));
+
+            System.out.println("These things are on the bus:");
+            String[] names = dbus.ListNames();
+            for (String name : names)
+                System.out.println("\t" + name);
+
+            System.out.println("Getting our introspection data");
+            /** This gets a remote object matching our bus name and exported object path. */
+            Introspectable intro = clientconn.getRemoteObject("foo.bar.Test", "/", Introspectable.class);
+            /** Get introspection data */
+            String data;/* = intro.Introspect();
+      if (null == data || !data.startsWith("<!DOCTYPE"))
+         fail("Introspection data invalid");
+      System.out.println("Got Introspection Data: \n"+data);*/
+            intro = clientconn.getRemoteObject("foo.bar.Test", "/Test", Introspectable.class);
+            /** Get introspection data */
+            data = intro.Introspect();
+            if (null == data || !data.startsWith("<!DOCTYPE"))
+                fail("Introspection data invalid");
+            System.out.println("Got Introspection Data: \n" + data);
+
+            // setup bus name set
+            Set<String> peers = serverconn.new PeerSet();
+            peers.add("org.freedesktop.DBus");
+            clientconn.requestBusName("test.testclient");
+            peers.add("test.testclient");
+            clientconn.releaseBusName("test.testclient");
+
+            System.out.println("Pinging ourselves");
+            /** Call ping. */
+            for (int i = 0; i < 10; i++) {
+                long then = System.currentTimeMillis();
+                peer.Ping();
+                long now = System.currentTimeMillis();
+                System.out.println("Ping returned in " + (now - then) + "ms.");
+            }
+
+            System.out.println("Calling Method0/1");
+            /** This gets a remote object matching our bus name and exported object path. */
+            TestRemoteInterface tri = (TestRemoteInterface) clientconn.getPeerRemoteObject("foo.bar.Test", "/Test");
+            System.out.println("Got Remote Object: " + tri);
+            /** Call the remote object and get a response. */
+            String rname = tri.getName();
+            System.out.println("Got Remote Name: " + rname);
+
+            Map<String, Variant> svmmap = tri.svm();
+            System.out.println(svmmap.toString());
+            if (!"{ Parameters => [{ Name => [Joe],Password => [abcdef] }] }".equals(svmmap.toString()))
+                fail("incorrect reply from svm");
+
+            Path path = new Path("/nonexistantwooooooo");
+            Path p = tri.pathrv(path);
+            System.out.println(path.toString() + " => " + p.toString());
+            if (!path.equals(p)) fail("pathrv incorrect");
+            List<Path> paths = new Vector<Path>();
+            paths.add(path);
+            List<Path> ps = tri.pathlistrv(paths);
+            System.out.println(paths.toString() + " => " + ps.toString());
+            if (!paths.equals(ps)) fail("pathlistrv incorrect");
+            Map<Path, Path> pathm = new HashMap<Path, Path>();
+            pathm.put(path, path);
+            Map<Path, Path> pm = tri.pathmaprv(pathm);
+            System.out.println(pathm.toString() + " => " + pm.toString());
+            System.out.println(pm.containsKey(path) + " " + pm.get(path) + " " + path.equals(pm.get(path)));
+            System.out.println(pm.containsKey(p) + " " + pm.get(p) + " " + p.equals(pm.get(p)));
+            for (Path q : pm.keySet()) {
+                System.out.println(q);
+                System.out.println(pm.get(q));
+            }
+            if (!pm.containsKey(path) || !path.equals(pm.get(path))) fail("pathmaprv incorrect");
+
+            serverconn.sendSignal(new TestSignalInterface.TestPathSignal("/Test", path, paths, pathm));
+
+            Collator col = Collator.getInstance();
+            col.setDecomposition(Collator.FULL_DECOMPOSITION);
+            col.setStrength(Collator.PRIMARY);
+            if (0 != col.compare("This Is A UTF-8 Name: ﺱ !!", rname))
+                fail("getName return value incorrect");
+            System.out.println("sending it to sleep");
+            tri.waitawhile();
+            System.out.println("testing floats");
+            if (17.093f != tri.testfloat(new float[]{17.093f, -23f, 0.0f, 31.42f}))
+                fail("testfloat returned the wrong thing");
+            System.out.println("Structs of Structs");
+            List<List<Integer>> lli = new Vector<List<Integer>>();
+            List<Integer> li = new Vector<Integer>();
+            li.add(1);
+            li.add(2);
+            li.add(3);
+            lli.add(li);
+            lli.add(li);
+            lli.add(li);
+            TestStruct3 ts3 = new TestStruct3(new TestStruct2(new Vector<String>(), new Variant<Integer>(0)), lli);
+            int[][] out = tri.teststructstruct(ts3);
+            if (out.length != 3) fail("teststructstruct returned the wrong thing: " + Arrays.deepToString(out));
+            for (int[] o : out)
+                if (o.length != 3
+                        || o[0] != 1
+                        || o[1] != 2
+                        || o[2] != 3) fail("teststructstruct returned the wrong thing: " + Arrays.deepToString(out));
+
+            System.out.println("frobnicating");
+            List<Long> ls = new Vector<Long>();
+            ls.add(2L);
+            ls.add(5L);
+            ls.add(71L);
+            Map<UInt16, Short> mus = new HashMap<UInt16, Short>();
+            mus.put(new UInt16(4), (short) 5);
+            mus.put(new UInt16(5), (short) 6);
+            mus.put(new UInt16(6), (short) 7);
+            Map<String, Map<UInt16, Short>> msmus = new HashMap<String, Map<UInt16, Short>>();
+            msmus.put("stuff", mus);
+            int rint = tri.frobnicate(ls, msmus, 13);
+            if (-5 != rint)
+                fail("frobnicate return value incorrect");
+
+            System.out.println("Doing stuff asynchronously with callback");
+            clientconn.callWithCallback(tri, "getName", new callbackhandler());
+            System.out.println("Doing stuff asynchronously with callback, which throws an error");
+            clientconn.callWithCallback(tri, "getNameAndThrow", new callbackhandler());
+
+            /** call something that throws */
+            try {
+                System.out.println("Throwing stuff");
+                tri.throwme();
+                test.fail("Method Execution should have failed");
+            } catch (TestException Te) {
+                System.out.println("Remote Method Failed with: " + Te.getClass().getName() + " " + Te.getMessage());
+                if (!Te.getMessage().equals("test"))
+                    test.fail("Error message was not correct");
+            }
+
+      /* Test type signatures */
+            Vector<Type> ts = new Vector<Type>();
+            Marshalling.getJavaType("ya{si}", ts, -1);
+            tri.sig(ts.toArray(new Type[0]));
+
+            tri.newpathtest(new Path("/new/path/test"));
+
+            /** Try and call an invalid remote object */
+            try {
+                System.out.println("Calling Method2");
+                tri = clientconn.getRemoteObject("foo.bar.NotATest", "/Moofle", TestRemoteInterface.class);
+                System.out.println("Got Remote Name: " + tri.getName());
+                test.fail("Method Execution should have failed");
+            } catch (ServiceUnknown SU) {
+                System.out.println("Remote Method Failed with: " + SU.getClass().getName() + " " + SU.getMessage());
+            }
+
+            /** Try and call an invalid remote object */
+            try {
+                System.out.println("Calling Method3");
+                tri = clientconn.getRemoteObject("foo.bar.Test", "/Moofle", TestRemoteInterface.class);
+                System.out.println("Got Remote Name: " + tri.getName());
+                test.fail("Method Execution should have failed");
+            } catch (UnknownObject UO) {
+                System.out.println("Remote Method Failed with: " + UO.getClass().getName() + " " + UO.getMessage());
+            }
+
+            /** Try and call an explicitly unexported object */
+            try {
+                System.out.println("Calling Method4");
+                tri = clientconn.getRemoteObject("foo.bar.Test", "/BadTest", TestRemoteInterface.class);
+                System.out.println("Got Remote Name: " + tri.getName());
+                test.fail("Method Execution should have failed");
+            } catch (UnknownObject UO) {
+                System.out.println("Remote Method Failed with: " + UO.getClass().getName() + " " + UO.getMessage());
+            }
+
+            /** Try and call an implicitly unexported object */
+            try {
+                System.out.println("Calling Method5");
+                tri = clientconn.getRemoteObject("foo.bar.Test", "/BadTest2", TestRemoteInterface.class);
+                System.out.println("Got Remote Name: " + tri.getName());
+                test.fail("Method Execution should have failed");
+            } catch (UnknownObject UO) {
+                System.out.println("Remote Method Failed with: " + UO.getClass().getName() + " " + UO.getMessage());
+            }
+
+            System.out.println("Calling Method6");
+            tri = clientconn.getRemoteObject("foo.bar.Test", "/FallbackTest/0/1", TestRemoteInterface.class);
+            intro = clientconn.getRemoteObject("foo.bar.Test", "/FallbackTest/0/4", Introspectable.class);
+            System.out.println("Got Fallback Name: " + tri.getName());
+            System.out.println("Fallback Introspection Data: \n" + intro.Introspect());
+
+            System.out.println("Testing Properties returning Paths");
+            Properties prop = clientconn.getRemoteObject("foo.bar.Test", "/Test", Properties.class);
+            Path prv = (Path) prop.Get("foo.bar", "foo");
+            System.out.println("Got path " + prv);
+            System.out.println("Calling Method7--9");
+            /** This gets a remote object matching our bus name and exported object path. */
+            TestRemoteInterface2 tri2 = clientconn.getRemoteObject("foo.bar.Test", "/Test", TestRemoteInterface2.class);
+            System.out.print("Calling the other introspect method: ");
+            String intro2 = tri2.Introspect();
+            System.out.println(intro2);
+            if (0 != col.compare("Not XML", intro2))
+                fail("Introspect return value incorrect");
+
+            /** Call the remote object and get a response. */
+            TestTuple<String, List<Integer>, Boolean> rv = tri2.show(234);
+            System.out.println("Show returned: " + rv);
+            if (!serverconn.getUniqueName().equals(rv.a) ||
+                    1 != rv.b.size() ||
+                    1953 != rv.b.get(0) ||
+                    true != rv.c.booleanValue())
+                fail("show return value incorrect (" + rv.a + "," + rv.b + "," + rv.c + ")");
+
+            System.out.println("Doing stuff asynchronously");
+            DBusAsyncReply<Boolean> stuffreply = (DBusAsyncReply<Boolean>) clientconn.callMethodAsync(tri2, "dostuff", new TestStruct("bar", new UInt32(52), new Variant<Boolean>(new Boolean(true))));
+
+            System.out.println("Checking bools");
+            if (tri2.check()) fail("bools are broken");
+
+            List<String> l = new Vector<String>();
+            l.add("hi");
+            l.add("hello");
+            l.add("hej");
+            l.add("hey");
+            l.add("aloha");
+            System.out.println("Sampling Arrays:");
+            List<Integer> is = tri2.sampleArray(l, new Integer[]{1, 5, 7, 9}, new long[]{2, 6, 8, 12});
+            System.out.println("sampleArray returned an array:");
+            for (Integer i : is)
+                System.out.println("--" + i);
+            if (is.size() != 5 ||
+                    is.get(0).intValue() != -1 ||
+                    is.get(1).intValue() != -5 ||
+                    is.get(2).intValue() != -7 ||
+                    is.get(3).intValue() != -12 ||
+                    is.get(4).intValue() != -18)
+                fail("sampleArray return value incorrect");
+
+            System.out.println("Get This");
+            if (!tclass.equals(tri2.getThis(tri2)))
+                fail("Didn't get the correct this");
+
+            Boolean b = stuffreply.getReply();
+            System.out.println("Do stuff replied " + b);
+            if (true != b.booleanValue())
+                fail("dostuff return value incorrect");
+
+            System.out.print("Sending Array Signal...");
+            /** This creates an instance of the Test Signal, with the given object path, signal name and parameters, and broadcasts in on the Bus. */
+            List<TestStruct2> tsl = new Vector<TestStruct2>();
+            tsl.add(new TestStruct2(l, new Variant<UInt64>(new UInt64(567))));
+            Map<UInt32, TestStruct2> tsm = new HashMap<UInt32, TestStruct2>();
+            tsm.put(new UInt32(1), new TestStruct2(l, new Variant<UInt64>(new UInt64(678))));
+            tsm.put(new UInt32(42), new TestStruct2(l, new Variant<UInt64>(new UInt64(789))));
+            serverconn.sendSignal(new TestSignalInterface.TestArraySignal("/Test", tsl, tsm));
+
+            System.out.println("done");
+
+            System.out.print("testing custom serialization...");
+            Vector<Integer> v = new Vector<Integer>();
+            v.add(1);
+            v.add(2);
+            v.add(3);
+            TestSerializable<String> s = new TestSerializable<String>(1, "woo", v);
+            s = tri2.testSerializable((byte) 12, s, 13);
+            System.out.print("returned: " + s);
+            if (s.getInt() != 1 ||
+                    !s.getString().equals("woo") ||
+                    s.getVector().size() != 3 ||
+                    s.getVector().get(0) != 1 ||
+                    s.getVector().get(1) != 2 ||
+                    s.getVector().get(2) != 3)
+                fail("Didn't get back the same TestSerializable");
+
+            System.out.println("done");
+
+            System.out.print("testing complex variants...");
+            Map m = new HashMap();
+            m.put("cow", "moo");
+            tri2.complexv(new Variant(m, "a{ss}"));
+            System.out.println("done");
+
+            System.out.print("testing recursion...");
+
+            if (0 != col.compare("This Is A UTF-8 Name: ﺱ !!", tri2.recursionTest())) fail("recursion test failed");
+
+            System.out.println("done");
+
+            System.out.print("testing method overloading...");
+            tri = clientconn.getRemoteObject("foo.bar.Test", "/Test", TestRemoteInterface.class);
+            if (1 != tri2.overload("foo")) test.fail("wrong overloaded method called");
+            if (2 != tri2.overload((byte) 0)) test.fail("wrong overloaded method called");
+            if (3 != tri2.overload()) test.fail("wrong overloaded method called");
+            if (4 != tri.overload()) test.fail("wrong overloaded method called");
+            System.out.println("done");
+
+            System.out.print("reg13291...");
+            byte[] as = new byte[10];
+            for (int i = 0; i < 10; i++)
+                as[i] = (byte) (100 - i);
+            tri.reg13291(as, as);
+            System.out.println("done");
+
+            System.out.print("Testing nested lists...");
+            lli = new Vector<List<Integer>>();
+            li = new Vector<Integer>();
+            li.add(1);
+            lli.add(li);
+            List<List<Integer>> reti = tri2.checklist(lli);
+            if (reti.size() != 1 ||
+                    reti.get(0).size() != 1 ||
+                    reti.get(0).get(0) != 1)
+                test.fail("Failed to check nested lists");
+            System.out.println("done");
+
+            System.out.print("Testing dynamic object creation...");
+            TestNewInterface tni = tri2.getNew();
+            System.out.print(tni.getName() + " ");
+            System.out.println("done");
+
+      /* send an object in a signal */
+            serverconn.sendSignal(new TestSignalInterface.TestObjectSignal("/foo/bar/Wibble", tclass));
+
+            /** Pause while we wait for the DBus messages to go back and forth. */
+            Thread.sleep(1000);
+
+            // check that bus name set has been trimmed
+            if (peers.size() != 1) fail("peers hasn't been trimmed");
+            if (!peers.contains("org.freedesktop.DBus")) fail("peers contains the wrong name");
+
+            System.out.println("Checking for outstanding errors");
+            DBusExecutionException DBEe = serverconn.getError();
+            if (null != DBEe) throw DBEe;
+            DBEe = clientconn.getError();
+            if (null != DBEe) throw DBEe;
+
+            System.out.println("Disconnecting");
+            /** Disconnect from the bus. */
+            clientconn.disconnect();
+            serverconn.disconnect();
+
+            System.out.println("Trying to do things after disconnection");
+
+            /** Remove sig handler */
+            clientconn.removeSigHandler(TestSignalInterface.TestSignal.class, sigh);
+
+            /** Call a method when disconnected */
+            try {
+                System.out.println("getName() suceeded and returned: " + tri.getName());
+                fail("Should not succeed when disconnected");
+            } catch (NotConnected NC) {
+                System.out.println("getName() failed with exception " + NC);
+            }
+            clientconn = null;
+            serverconn = null;
+
+            if (!done1) fail("Signal handler 1 failed to be run");
+            if (!done2) fail("Signal handler 2 failed to be run");
+            if (!done3) fail("Signal handler 3 failed to be run");
+            if (!done4) fail("Callback handler failed to be run");
+            if (!done5) fail("Signal handler R failed to be run");
+            if (!done6) fail("Disconnect handler failed to be run");
+            if (!done7) fail("Signal handler E failed to be run");
+            if (!done8) fail("Error callback handler failed to be run");
+
+        } catch (Exception e) {
+            e.printStackTrace();
+            fail("Unexpected Exception Occurred: " + e);
+        }
+    }
+}
                diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/test_low_level.java b/federation/sssd/src/test/java/org/freedesktop/dbus/test_low_level.java
new file mode 100644
index 0000000..71699eb
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/test_low_level.java
@@ -0,0 +1,50 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import cx.ath.matthew.debug.Debug;
+
+public class test_low_level {
+    public static void main(String[] args) throws Exception {
+        Debug.setHexDump(true);
+        String addr = System.getenv("DBUS_SESSION_BUS_ADDRESS");
+        Debug.print(addr);
+        BusAddress address = new BusAddress(addr);
+        Debug.print(address);
+
+        Transport conn = new Transport(address);
+
+        Message m = new MethodCall("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "Hello", (byte) 0, null);
+        conn.mout.writeMessage(m);
+        m = conn.min.readMessage();
+        Debug.print(m.getClass());
+        Debug.print(m);
+        m = conn.min.readMessage();
+        Debug.print(m.getClass());
+        Debug.print(m);
+        m = conn.min.readMessage();
+        Debug.print("" + m);
+        m = new MethodCall("org.freedesktop.DBus", "/", null, "Hello", (byte) 0, null);
+        conn.mout.writeMessage(m);
+        m = conn.min.readMessage();
+        Debug.print(m);
+
+        m = new MethodCall("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "RequestName", (byte) 0, "su", "org.testname", 0);
+        conn.mout.writeMessage(m);
+        m = conn.min.readMessage();
+        Debug.print(m);
+        m = new DBusSignal(null, "/foo", "org.foo", "Foo", null);
+        conn.mout.writeMessage(m);
+        m = conn.min.readMessage();
+        Debug.print(m);
+        conn.disconnect();
+    }
+}
                diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/TestException.java b/federation/sssd/src/test/java/org/freedesktop/dbus/TestException.java
new file mode 100644
index 0000000..98335c8
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/TestException.java
@@ -0,0 +1,22 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.DBus.Description;
+import org.freedesktop.dbus.exceptions.DBusExecutionException;
+
+@Description("A test exception to throw over DBus")
+@SuppressWarnings("serial")
+public class TestException extends DBusExecutionException {
+    public TestException(String message) {
+        super(message);
+    }
+}
                diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/TestNewInterface.java b/federation/sssd/src/test/java/org/freedesktop/dbus/TestNewInterface.java
new file mode 100644
index 0000000..6395787
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/TestNewInterface.java
@@ -0,0 +1,24 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.DBus.Description;
+
+/**
+ * A sample remote interface which exports one method.
+ */
+public interface TestNewInterface extends DBusInterface {
+    /**
+     * A simple method with no parameters which returns a String
+     */
+    @Description("Simple test method")
+    public String getName();
+}
                diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/TestRemoteInterface.java b/federation/sssd/src/test/java/org/freedesktop/dbus/TestRemoteInterface.java
new file mode 100644
index 0000000..6fec592
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/TestRemoteInterface.java
@@ -0,0 +1,68 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.DBus.Description;
+import org.freedesktop.DBus.Method;
+
+import java.lang.reflect.Type;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A sample remote interface which exports one method.
+ */
+public interface TestRemoteInterface extends DBusInterface {
+    /**
+     * A simple method with no parameters which returns a String
+     */
+    @Description("Simple test method")
+    public String getName();
+
+    public String getNameAndThrow();
+
+    @Description("Test of nested maps")
+    public <T> int frobnicate(List<Long> n, Map<String, Map<UInt16, Short>> m, T v);
+
+    @Description("Throws a TestException when called")
+    public void throwme() throws TestException;
+
+    @Description("Waits then doesn't return")
+    @Method.NoReply()
+    public void waitawhile();
+
+    @Description("Interface-overloaded method")
+    public int overload();
+
+    @Description("Testing Type Signatures")
+    public void sig(Type[] s);
+
+    @Description("Testing object paths as Path objects")
+    public void newpathtest(Path p);
+
+    @Description("Testing the float type")
+    public float testfloat(float[] f);
+
+    @Description("Testing structs of structs")
+    public int[][] teststructstruct(TestStruct3 in);
+
+    @Description("Regression test for #13291")
+    public void reg13291(byte[] as, byte[] bs);
+
+    public Map<String, Variant> svm();
+
+    /* test lots of things involving Path */
+    public Path pathrv(Path a);
+
+    public List<Path> pathlistrv(List<Path> a);
+
+    public Map<Path, Path> pathmaprv(Map<Path, Path> a);
+}
                diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/TestRemoteInterface2.java b/federation/sssd/src/test/java/org/freedesktop/dbus/TestRemoteInterface2.java
new file mode 100644
index 0000000..7039fe1
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/TestRemoteInterface2.java
@@ -0,0 +1,62 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.DBus.Description;
+
+import java.util.List;
+
+@Description("An example remote interface")
+@DBusInterfaceName("org.freedesktop.dbus.test.AlternateTestInterface")
+public interface TestRemoteInterface2 extends DBusInterface {
+    @Description("Test multiple return values and implicit variant parameters.")
+    public <A> TestTuple<String, List<Integer>, Boolean> show(A in);
+
+    @Description("Test passing structs and explicit variants, returning implicit variants")
+    public <T> T dostuff(TestStruct foo);
+
+    @Description("Test arrays, boxed arrays and lists.")
+    public List<Integer> sampleArray(List<String> l, Integer[] is, long[] ls);
+
+    @Description("Test passing objects as object paths.")
+    public DBusInterface getThis(DBusInterface t);
+
+    @Description("Test bools work")
+    @DBusMemberName("checkbool")
+    public boolean check();
+
+    @Description("Test Serializable Object")
+    public TestSerializable<String> testSerializable(byte b, TestSerializable<String> s, int i);
+
+    @Description("Call another method on itself from within a call")
+    public String recursionTest();
+
+    @Description("Parameter-overloaded method (string)")
+    public int overload(String s);
+
+    @Description("Parameter-overloaded method (byte)")
+    public int overload(byte b);
+
+    @Description("Parameter-overloaded method (void)")
+    public int overload();
+
+    @Description("Nested List Check")
+    public List<List<Integer>> checklist(List<List<Integer>> lli);
+
+    @Description("Get new objects as object paths.")
+    public TestNewInterface getNew();
+
+    @Description("Test Complex Variants")
+    public void complexv(Variant<? extends Object> v);
+
+    @Description("Test Introspect on a different interface")
+    public String Introspect();
+}
                diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/TestSerializable.java b/federation/sssd/src/test/java/org/freedesktop/dbus/TestSerializable.java
new file mode 100644
index 0000000..0a8275a
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/TestSerializable.java
@@ -0,0 +1,57 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.dbus.exceptions.DBusException;
+
+import java.util.List;
+import java.util.Vector;
+
+public class TestSerializable<A> implements DBusSerializable {
+    private int a;
+    private String b;
+    private Vector<Integer> c;
+
+    public TestSerializable(int a, A b, Vector<Integer> c) {
+        this.a = a;
+        this.b = b.toString();
+        this.c = c;
+    }
+
+    public TestSerializable() {
+    }
+
+    public void deserialize(int a, String b, List<Integer> c) {
+        this.a = a;
+        this.b = b;
+        this.c = new Vector<Integer>(c);
+    }
+
+    public Object[] serialize() throws DBusException {
+        return new Object[]{a, b, c};
+    }
+
+    public int getInt() {
+        return a;
+    }
+
+    public String getString() {
+        return b;
+    }
+
+    public Vector<Integer> getVector() {
+        return c;
+    }
+
+    public String toString() {
+        return "TestSerializable{" + a + "," + b + "," + c + "}";
+    }
+}
                diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/TestSignalInterface.java b/federation/sssd/src/test/java/org/freedesktop/dbus/TestSignalInterface.java
new file mode 100644
index 0000000..518a5db
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/TestSignalInterface.java
@@ -0,0 +1,89 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.DBus.Description;
+import org.freedesktop.dbus.exceptions.DBusException;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A sample signal with two parameters
+ */
+@Description("Test interface containing signals")
+public interface TestSignalInterface extends DBusInterface {
+    @Description("Test basic signal")
+    public static class TestSignal extends DBusSignal {
+        public final String value;
+        public final UInt32 number;
+
+        /**
+         * Create a signal.
+         */
+        public TestSignal(String path, String value, UInt32 number) throws DBusException {
+            super(path, value, number);
+            this.value = value;
+            this.number = number;
+        }
+    }
+
+    public static class StringSignal extends DBusSignal {
+        public final String aoeu;
+
+        public StringSignal(String path, String aoeu) throws DBusException {
+            super(path, aoeu);
+            this.aoeu = aoeu;
+        }
+    }
+
+    public static class EmptySignal extends DBusSignal {
+        public EmptySignal(String path) throws DBusException {
+            super(path);
+        }
+    }
+
+    @Description("Test signal with arrays")
+    public static class TestArraySignal extends DBusSignal {
+        public final List<TestStruct2> v;
+        public final Map<UInt32, TestStruct2> m;
+
+        public TestArraySignal(String path, List<TestStruct2> v, Map<UInt32, TestStruct2> m) throws DBusException {
+            super(path, v, m);
+            this.v = v;
+            this.m = m;
+        }
+    }
+
+    @Description("Test signal sending an object path")
+    @DBusMemberName("TestSignalObject")
+    public static class TestObjectSignal extends DBusSignal {
+        public final DBusInterface otherpath;
+
+        public TestObjectSignal(String path, DBusInterface otherpath) throws DBusException {
+            super(path, otherpath);
+            this.otherpath = otherpath;
+        }
+    }
+
+    public static class TestPathSignal extends DBusSignal {
+        public final Path otherpath;
+        public final List<Path> pathlist;
+        public final Map<Path, Path> pathmap;
+
+        public TestPathSignal(String path, Path otherpath, List<Path> pathlist, Map<Path, Path> pathmap) throws DBusException {
+            super(path, otherpath, pathlist, pathmap);
+            this.otherpath = otherpath;
+            this.pathlist = pathlist;
+            this.pathmap = pathmap;
+        }
+    }
+}
                diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/TestSignalInterface2.java b/federation/sssd/src/test/java/org/freedesktop/dbus/TestSignalInterface2.java
new file mode 100644
index 0000000..9324b40
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/TestSignalInterface2.java
@@ -0,0 +1,36 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.DBus.Description;
+import org.freedesktop.dbus.exceptions.DBusException;
+
+/**
+ * A sample signal with two parameters
+ */
+@Description("Test interface containing signals")
+@DBusInterfaceName("some.other.interface.Name")
+public interface TestSignalInterface2 extends DBusInterface {
+    @Description("Test basic signal")
+    public static class TestRenamedSignal extends DBusSignal {
+        public final String value;
+        public final UInt32 number;
+
+        /**
+         * Create a signal.
+         */
+        public TestRenamedSignal(String path, String value, UInt32 number) throws DBusException {
+            super(path, value, number);
+            this.value = value;
+            this.number = number;
+        }
+    }
+}
                diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/TestStruct.java b/federation/sssd/src/test/java/org/freedesktop/dbus/TestStruct.java
new file mode 100644
index 0000000..09f42fc
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/TestStruct.java
@@ -0,0 +1,26 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+public final class TestStruct extends Struct {
+    @Position(0)
+    public final String a;
+    @Position(1)
+    public final UInt32 b;
+    @Position(2)
+    public final Variant<? extends Object> c;
+
+    public TestStruct(String a, UInt32 b, Variant<? extends Object> c) {
+        this.a = a;
+        this.b = b;
+        this.c = c;
+    }
+}
                diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/TestStruct2.java b/federation/sssd/src/test/java/org/freedesktop/dbus/TestStruct2.java
new file mode 100644
index 0000000..efd0d87
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/TestStruct2.java
@@ -0,0 +1,27 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.dbus.exceptions.DBusException;
+
+import java.util.List;
+
+public final class TestStruct2 extends Struct {
+    @Position(0)
+    public final List<String> a;
+    @Position(1)
+    public final Variant<? extends Object> b;
+
+    public TestStruct2(List<String> a, Variant<? extends Object> b) throws DBusException {
+        this.a = a;
+        this.b = b;
+    }
+}
                diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/TestStruct3.java b/federation/sssd/src/test/java/org/freedesktop/dbus/TestStruct3.java
new file mode 100644
index 0000000..d457053
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/TestStruct3.java
@@ -0,0 +1,27 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.dbus.exceptions.DBusException;
+
+import java.util.List;
+
+public final class TestStruct3 extends Struct {
+    @Position(0)
+    public final TestStruct2 a;
+    @Position(1)
+    public final List<List<Integer>> b;
+
+    public TestStruct3(TestStruct2 a, List<List<Integer>> b) throws DBusException {
+        this.a = a;
+        this.b = b;
+    }
+}
                diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/TestTuple.java b/federation/sssd/src/test/java/org/freedesktop/dbus/TestTuple.java
new file mode 100644
index 0000000..4adb0d8
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/TestTuple.java
@@ -0,0 +1,26 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+public final class TestTuple<A, B, C> extends Tuple {
+    @Position(0)
+    public final A a;
+    @Position(1)
+    public final B b;
+    @Position(2)
+    public final C c;
+
+    public TestTuple(A a, B b, C c) {
+        this.a = a;
+        this.b = b;
+        this.c = c;
+    }
+}
                diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/two_part_test_client.java b/federation/sssd/src/test/java/org/freedesktop/dbus/two_part_test_client.java
new file mode 100644
index 0000000..75f4bd8
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/two_part_test_client.java
@@ -0,0 +1,43 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+public class two_part_test_client {
+    public static class two_part_test_object implements TwoPartObject {
+        public boolean isRemote() {
+            return false;
+        }
+
+        public String getName() {
+            System.out.println("client name");
+            return toString();
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        System.out.println("get conn");
+        DBusConnection conn = DBusConnection.getConnection(DBusConnection.SESSION);
+        System.out.println("get remote");
+        TwoPartInterface remote = conn.getRemoteObject("org.freedesktop.dbus.test.two_part_server", "/", TwoPartInterface.class);
+        System.out.println("get object");
+        TwoPartObject o = remote.getNew();
+        System.out.println("get name");
+        System.out.println(o.getName());
+        two_part_test_object tpto = new two_part_test_object();
+        conn.exportObject("/TestObject", tpto);
+        conn.sendSignal(new TwoPartInterface.TwoPartSignal("/FromObject", tpto));
+        try {
+            Thread.sleep(1000);
+        } catch (InterruptedException Ie) {
+        }
+        conn.disconnect();
+    }
+}
                diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/two_part_test_server.java b/federation/sssd/src/test/java/org/freedesktop/dbus/two_part_test_server.java
new file mode 100644
index 0000000..c0b1ded
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/two_part_test_server.java
@@ -0,0 +1,62 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+public class two_part_test_server implements TwoPartInterface, DBusSigHandler<TwoPartInterface.TwoPartSignal> {
+    public class two_part_test_object implements TwoPartObject {
+        public boolean isRemote() {
+            return false;
+        }
+
+        public String getName() {
+            System.out.println("give name");
+            return toString();
+        }
+    }
+
+    private DBusConnection conn;
+
+    public two_part_test_server(DBusConnection conn) {
+        this.conn = conn;
+    }
+
+    public boolean isRemote() {
+        return false;
+    }
+
+    public TwoPartObject getNew() {
+        TwoPartObject o = new two_part_test_object();
+        System.out.println("export new");
+        try {
+            conn.exportObject("/12345", o);
+        } catch (Exception e) {
+        }
+        System.out.println("give new");
+        return o;
+    }
+
+    public void handle(TwoPartInterface.TwoPartSignal s) {
+        System.out.println("Got: " + s.o);
+    }
+
+    public static void main(String[] args) throws Exception {
+        DBusConnection conn = DBusConnection.getConnection(DBusConnection.SESSION);
+        conn.requestBusName("org.freedesktop.dbus.test.two_part_server");
+        two_part_test_server server = new two_part_test_server(conn);
+        conn.exportObject("/", server);
+        conn.addSigHandler(TwoPartInterface.TwoPartSignal.class, server);
+        while (true) try {
+            Thread.sleep(10000);
+        } catch (InterruptedException Ie) {
+        }
+    }
+}
+
                diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/TwoPartInterface.java b/federation/sssd/src/test/java/org/freedesktop/dbus/TwoPartInterface.java
new file mode 100644
index 0000000..242dcb2
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/TwoPartInterface.java
@@ -0,0 +1,26 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.dbus.exceptions.DBusException;
+
+public interface TwoPartInterface extends DBusInterface {
+    public TwoPartObject getNew();
+
+    public class TwoPartSignal extends DBusSignal {
+        public final TwoPartObject o;
+
+        public TwoPartSignal(String path, TwoPartObject o) throws DBusException {
+            super(path, o);
+            this.o = o;
+        }
+    }
+}
                diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/TwoPartObject.java b/federation/sssd/src/test/java/org/freedesktop/dbus/TwoPartObject.java
new file mode 100644
index 0000000..8f03bbc
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/TwoPartObject.java
@@ -0,0 +1,15 @@
+/*
+   D-Bus Java Implementation
+   Copyright (c) 2005-2006 Matthew Johnson
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of either the GNU Lesser General Public License Version 2 or the
+   Academic Free Licence Version 2.1.
+
+   Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+public interface TwoPartObject extends DBusInterface {
+    public String getName();
+}
                diff --git a/federation/sssd/src/test/java/org/jvnet/libpam/InteractiveTester.java b/federation/sssd/src/test/java/org/jvnet/libpam/InteractiveTester.java
new file mode 100644
index 0000000..47fef18
--- /dev/null
+++ b/federation/sssd/src/test/java/org/jvnet/libpam/InteractiveTester.java
@@ -0,0 +1,95 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package org.jvnet.libpam;
+
+import junit.framework.TestCase;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+public class InteractiveTester extends TestCase {
+    public InteractiveTester(String testName) {
+        super(testName);
+    }
+
+    public void testPositiveCase() throws Exception {
+        for (int i = 0; i < 1000; i++)
+            testOne();
+    }
+
+    public void testOne() throws Exception {
+        UnixUser u = new PAM("sshd").authenticate(System.getProperty("user.name"), System.getProperty("password"));
+        if (!printOnce) {
+            System.out.println(u.getUID());
+            System.out.println(u.getGroups());
+            printOnce = true;
+        }
+    }
+
+    public void testGetGroups() throws Exception {
+        System.out.println(new PAM("sshd").getGroupsOfUser(System.getProperty("user.name")));
+    }
+
+    public void testConcurrent() throws Exception {
+        ExecutorService es = Executors.newFixedThreadPool(10);
+        Set<Future<?>> result = new HashSet<Future<?>>();
+        for (int i = 0; i < 1000; i++) {
+            result.add(es.submit(new Callable<Object>() {
+                public Object call() throws Exception {
+                    testOne();
+                    return null;
+                }
+            }));
+        }
+        // wait for completion
+        for (Future<?> f : result) {
+            f.get();
+        }
+        es.shutdown();
+    }
+
+    public void testNegative() throws Exception {
+        try {
+            new PAM("sshd").authenticate("bogus", "bogus");
+            fail("expected a failure");
+        } catch (PAMException e) {
+            // yep
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        UnixUser u = new PAM("sshd").authenticate(args[0], args[1]);
+        System.out.println(u.getUID());
+        System.out.println(u.getGroups());
+        System.out.println(u.getGecos());
+        System.out.println(u.getDir());
+        System.out.println(u.getShell());
+    }
+
+    private boolean printOnce;
+}
                diff --git a/federation/sssd/src/test/java/org/jvnet/libpam/UnixUserTest.java b/federation/sssd/src/test/java/org/jvnet/libpam/UnixUserTest.java
new file mode 100644
index 0000000..4b3e5f5
--- /dev/null
+++ b/federation/sssd/src/test/java/org/jvnet/libpam/UnixUserTest.java
@@ -0,0 +1,52 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2014, R. Tyler Croy
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package org.jvnet.libpam;
+
+import junit.framework.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class UnixUserTest {
+    private UnixUser user = null;
+
+    @Before
+    public void setUp() throws PAMException {
+        user = new UnixUser("root");
+    }
+
+    @Test
+    public void testGetUserName() {
+        Assert.assertEquals("root", user.getUserName());
+    }
+
+    @Test
+    public void testGetDir() {
+        Assert.assertNotNull(user.getDir());
+    }
+
+    @Test
+    public void testGetUID() {
+        Assert.assertEquals(0, user.getUID());
+    }
+}
                diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserAttributeEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserAttributeEntity.java
index 2b5d35c..16b155b 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserAttributeEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserAttributeEntity.java
@@ -43,6 +43,7 @@ import java.util.Set;
         @NamedQuery(name="getAttributesByNameAndValue", query="select attr from UserAttributeEntity attr where attr.name = :name and attr.value = :value"),
         @NamedQuery(name="deleteUserAttributesByRealm", query="delete from  UserAttributeEntity attr where attr.user IN (select u from UserEntity u where u.realmId=:realmId)"),
         @NamedQuery(name="deleteUserAttributesByNameAndUser", query="delete from  UserAttributeEntity attr where attr.user.id = :userId and attr.name = :name"),
+        @NamedQuery(name="deleteUserAttributesOtherThan", query="delete from  UserAttributeEntity attr where attr.user.id = :userId and attr.id <> :attrId"),
         @NamedQuery(name="deleteUserAttributesByRealmAndLink", query="delete from  UserAttributeEntity attr where attr.user IN (select u from UserEntity u where u.realmId=:realmId and u.federationLink=:link)")
 })
 @Table(name="USER_ATTRIBUTE")
                diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java
index 2ea12fd..49bcac6 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java
@@ -125,29 +125,32 @@ public class UserAdapter implements UserModel, JpaModel<UserEntity> {
 
     @Override
     public void setSingleAttribute(String name, String value) {
-        boolean found = false;
+        String firstExistingAttrId = null;
         List<UserAttributeEntity> toRemove = new ArrayList<>();
         for (UserAttributeEntity attr : user.getAttributes()) {
             if (attr.getName().equals(name)) {
-                if (!found) {
+                if (firstExistingAttrId == null) {
                     attr.setValue(value);
-                    found = true;
+                    firstExistingAttrId = attr.getId();
                 } else {
                     toRemove.add(attr);
                 }
             }
         }
 
-        for (UserAttributeEntity attr : toRemove) {
-            em.remove(attr);
-            user.getAttributes().remove(attr);
-        }
+        if (firstExistingAttrId != null) {
+            // Remove attributes through HQL to avoid StaleUpdateException
+            Query query = em.createNamedQuery("deleteUserAttributesOtherThan");
+            query.setParameter("attrId", firstExistingAttrId);
+            query.setParameter("userId", user.getId());
+            int numUpdated = query.executeUpdate();
 
-        if (found) {
-            return;
-        }
+            // Remove attribute from local entity
+            user.getAttributes().removeAll(toRemove);
+        } else {
 
-        persistAttributeValue(name, value);
+            persistAttributeValue(name, value);
+        }
     }
 
     @Override
@@ -178,6 +181,15 @@ public class UserAdapter implements UserModel, JpaModel<UserEntity> {
         query.setParameter("name", name);
         query.setParameter("userId", user.getId());
         int numUpdated = query.executeUpdate();
+
+        // KEYCLOAK-3494 : Also remove attributes from local user entity
+        List<UserAttributeEntity> toRemove = new ArrayList<>();
+        for (UserAttributeEntity attr : user.getAttributes()) {
+            if (attr.getName().equals(name)) {
+                toRemove.add(attr);
+            }
+        }
+        user.getAttributes().removeAll(toRemove);
     }
 
     @Override
                pom.xml 12(+12 -0)
diff --git a/pom.xml b/pom.xml
index 7208837..48e8a65 100755
--- a/pom.xml
+++ b/pom.xml
@@ -94,6 +94,7 @@
         <mariadb.version>1.3.7</mariadb.version>
         <servlet.api.30.version>1.0.2.Final</servlet.api.30.version>
         <twitter4j.version>4.0.4</twitter4j.version>
+        <jna.version>4.1.0</jna.version>
 
         <!-- Test -->
         <greenmail.version>1.3.1b</greenmail.version>
@@ -685,6 +686,17 @@
                 <artifactId>keycloak-kerberos-federation</artifactId>
                 <version>${project.version}</version>
             </dependency>
+            <!-- Dependencies for RHEL IdM -->
+            <dependency>
+                <groupId>org.keycloak</groupId>
+                <artifactId>keycloak-sssd-federation</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>net.java.dev.jna</groupId>
+                <artifactId>jna</artifactId>
+                <version>${jna.version}</version>
+            </dependency>
             <dependency>
                 <groupId>org.keycloak</groupId>
                 <artifactId>keycloak-ldap-federation</artifactId>
                diff --git a/server-spi/src/main/java/org/keycloak/models/Constants.java b/server-spi/src/main/java/org/keycloak/models/Constants.java
index 916565a..42982f6 100755
--- a/server-spi/src/main/java/org/keycloak/models/Constants.java
+++ b/server-spi/src/main/java/org/keycloak/models/Constants.java
@@ -50,5 +50,5 @@ public interface Constants {
     String KEY = "key";
 
     // Prefix for user attributes used in various "context"data maps
-    public static final String USER_ATTRIBUTES_PREFIX = "user.attributes.";
+    String USER_ATTRIBUTES_PREFIX = "user.attributes.";
 }
                diff --git a/services/src/main/java/org/keycloak/forms/account/freemarker/model/AccountBean.java b/services/src/main/java/org/keycloak/forms/account/freemarker/model/AccountBean.java
index acb1514..857bfc0 100755
--- a/services/src/main/java/org/keycloak/forms/account/freemarker/model/AccountBean.java
+++ b/services/src/main/java/org/keycloak/forms/account/freemarker/model/AccountBean.java
@@ -18,6 +18,7 @@
 package org.keycloak.forms.account.freemarker.model;
 
 import org.jboss.logging.Logger;
+import org.keycloak.models.Constants;
 import org.keycloak.models.UserModel;
 
 import javax.ws.rs.core.MultivaluedMap;
@@ -55,8 +56,8 @@ public class AccountBean {
 
         if (profileFormData != null) {
             for (String key : profileFormData.keySet()) {
-                if (key.startsWith("user.attributes.")) {
-                    String attribute = key.substring("user.attributes.".length());
+                if (key.startsWith(Constants.USER_ATTRIBUTES_PREFIX)) {
+                    String attribute = key.substring(Constants.USER_ATTRIBUTES_PREFIX.length());
                     attributes.put(attribute, profileFormData.getFirst(key));
                 }
             }
                testsuite/integration/pom.xml 8(+8 -0)
diff --git a/testsuite/integration/pom.xml b/testsuite/integration/pom.xml
index aca1d78..92187bc 100755
--- a/testsuite/integration/pom.xml
+++ b/testsuite/integration/pom.xml
@@ -166,6 +166,14 @@
             <groupId>org.keycloak</groupId>
             <artifactId>federation-properties-example</artifactId>
         </dependency>
+
+        <!-- Dependency on services from integration-arquillian -->
+        <dependency>
+            <groupId>org.keycloak.testsuite</groupId>
+            <artifactId>integration-arquillian-testsuite-providers</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
         <dependency>
             <groupId>org.jboss.logging</groupId>
             <artifactId>jboss-logging</artifactId>
                diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractKeycloakIdentityProviderTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractKeycloakIdentityProviderTest.java
index 7683d0c..f6a85e4 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractKeycloakIdentityProviderTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractKeycloakIdentityProviderTest.java
@@ -45,8 +45,8 @@ import org.keycloak.models.UserFederationProviderModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.representations.idm.IdentityProviderRepresentation;
 import org.keycloak.services.Urls;
-import org.keycloak.testsuite.DummyUserFederationProviderFactory;
 import org.keycloak.testsuite.broker.util.UserSessionStatusServlet;
+import org.keycloak.testsuite.federation.DummyUserFederationProviderFactory;
 import org.openqa.selenium.By;
 import org.openqa.selenium.NoSuchElementException;
 
                diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/sync/SyncDummyUserFederationProviderFactory.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/sync/SyncDummyUserFederationProviderFactory.java
index 5d327f4..3831787 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/sync/SyncDummyUserFederationProviderFactory.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/sync/SyncDummyUserFederationProviderFactory.java
@@ -32,7 +32,7 @@ import org.keycloak.models.UserFederationProviderModel;
 import org.keycloak.models.UserFederationSyncResult;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.utils.KeycloakModelUtils;
-import org.keycloak.testsuite.DummyUserFederationProviderFactory;
+import org.keycloak.testsuite.federation.DummyUserFederationProviderFactory;
 
 /**
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
                diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/sync/SyncFederationTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/sync/SyncFederationTest.java
index 84a901a..efa688c 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/sync/SyncFederationTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/sync/SyncFederationTest.java
@@ -36,7 +36,7 @@ import org.keycloak.models.UserFederationProviderModel;
 import org.keycloak.models.UserFederationSyncResult;
 import org.keycloak.services.managers.RealmManager;
 import org.keycloak.services.managers.UsersSyncManager;
-import org.keycloak.testsuite.DummyUserFederationProviderFactory;
+import org.keycloak.testsuite.federation.DummyUserFederationProviderFactory;
 import org.keycloak.testsuite.rule.KeycloakRule;
 import org.keycloak.timer.TimerProvider;
 
                diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ConcurrentTransactionsTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ConcurrentTransactionsTest.java
index b3ad0c4..2fb2aaf 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ConcurrentTransactionsTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ConcurrentTransactionsTest.java
@@ -17,6 +17,7 @@
 
 package org.keycloak.testsuite.model;
 
+import java.util.Arrays;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.atomic.AtomicReference;
 
@@ -151,14 +152,17 @@ public class ConcurrentTransactionsTest extends AbstractModelTest {
     }
 
 
-    // KEYCLOAK-3296
+    // KEYCLOAK-3296 , KEYCLOAK-3494
     @Test
     public void removeUserAttribute() throws Exception {
         RealmModel realm = realmManager.createRealm("original");
         KeycloakSession session = realmManager.getSession();
 
-        UserModel user = session.users().addUser(realm, "john");
-        user.setSingleAttribute("foo", "val1");
+        UserModel john = session.users().addUser(realm, "john");
+        john.setSingleAttribute("foo", "val1");
+
+        UserModel john2 = session.users().addUser(realm, "john2");
+        john2.setAttribute("foo", Arrays.asList("val1", "val2"));
 
         final KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
         commit();
@@ -182,12 +186,18 @@ public class ConcurrentTransactionsTest extends AbstractModelTest {
                                 UserModel john = session.users().getUserByUsername("john", realm);
                                 String attrVal = john.getFirstAttribute("foo");
 
+                                UserModel john2 = session.users().getUserByUsername("john2", realm);
+                                String attrVal2 = john2.getFirstAttribute("foo");
+
                                 // Wait until it's read in both threads
                                 readAttrLatch.countDown();
                                 readAttrLatch.await();
 
-                                // Remove user attribute in both threads
+                                // KEYCLOAK-3296 : Remove user attribute in both threads
                                 john.removeAttribute("foo");
+
+                                // KEYCLOAK-3494 : Set single attribute in both threads
+                                john2.setSingleAttribute("foo", "bar");
                             } catch (Exception e) {
                                 throw new RuntimeException(e);
                             }
                diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserModelTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserModelTest.java
index 4b3f78e..e2af241 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserModelTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserModelTest.java
@@ -211,6 +211,31 @@ public class UserModelTest extends AbstractModelTest {
         Assert.assertEquals("val23", attrVals.get(0));
     }
 
+    // KEYCLOAK-3494
+    @Test
+    public void testUpdateUserAttribute() throws Exception {
+        RealmModel realm = realmManager.createRealm("original");
+        UserModel user = session.users().addUser(realm, "user");
+
+        user.setSingleAttribute("key1", "value1");
+
+        commit();
+
+        realm = realmManager.getRealmByName("original");
+        user = session.users().getUserByUsername("user", realm);
+
+        // Update attribute
+        List<String> attrVals = new ArrayList<>(Arrays.asList( "val2" ));
+        user.setAttribute("key1", attrVals);
+        Map<String, List<String>> allAttrVals = user.getAttributes();
+
+        // Ensure same transaction is able to see updated value
+        Assert.assertEquals(1, allAttrVals.size());
+        Assert.assertEquals(allAttrVals.get("key1"), Arrays.asList("val2"));
+
+        commit();
+    }
+
     @Test
     public void testSearchByString() {
         RealmModel realm = realmManager.createRealm("original");
                diff --git a/testsuite/integration/src/test/resources/META-INF/services/org.keycloak.models.UserFederationProviderFactory b/testsuite/integration/src/test/resources/META-INF/services/org.keycloak.models.UserFederationProviderFactory
index 1b4de73..d4a16d3 100755
--- a/testsuite/integration/src/test/resources/META-INF/services/org.keycloak.models.UserFederationProviderFactory
+++ b/testsuite/integration/src/test/resources/META-INF/services/org.keycloak.models.UserFederationProviderFactory
@@ -15,5 +15,4 @@
 # limitations under the License.
 #
 
-org.keycloak.testsuite.DummyUserFederationProviderFactory
 org.keycloak.testsuite.federation.sync.SyncDummyUserFederationProviderFactory
\ No newline at end of file
                diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/keycloak-server-subsystem.xsl b/testsuite/integration-arquillian/servers/auth-server/jboss/common/keycloak-server-subsystem.xsl
index f32c036..664eecb 100644
--- a/testsuite/integration-arquillian/servers/auth-server/jboss/common/keycloak-server-subsystem.xsl
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/keycloak-server-subsystem.xsl
@@ -36,6 +36,11 @@
             </provider>
         </spi>
     </xsl:variable>
+    <xsl:variable name="themeModuleDefinition">
+        <modules>
+            <module>org.keycloak.testsuite.integration-arquillian-testsuite-providers</module>
+        </modules>
+    </xsl:variable>
     
     <!--inject provider-->
     <xsl:template match="//*[local-name()='providers']/*[local-name()='provider']">
@@ -46,6 +51,14 @@
             <xsl:text>module:org.keycloak.testsuite.integration-arquillian-testsuite-providers</xsl:text>
         </provider>
     </xsl:template>
+
+    <!--inject provider for themes -->
+    <xsl:template match="//*[local-name()='theme']">
+        <xsl:copy>
+            <xsl:apply-templates select="@*|node()" />
+            <xsl:copy-of select="$themeModuleDefinition"/>
+        </xsl:copy>
+    </xsl:template>
     
     <!--inject truststore-->
     <xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsKS)]">
                diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/META-INF/keycloak-themes.json b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/META-INF/keycloak-themes.json
new file mode 100644
index 0000000..03978db
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/META-INF/keycloak-themes.json
@@ -0,0 +1,6 @@
+{
+  "themes": [{
+    "name" : "address",
+    "types": [ "admin", "account", "login" ]
+  }]
+}
\ No newline at end of file
                diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/account/account.ftl b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/account/account.ftl
new file mode 100755
index 0000000..d2a6af1
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/account/account.ftl
@@ -0,0 +1,114 @@
+<#import "template.ftl" as layout>
+<@layout.mainLayout active='account' bodyClass='user'; section>
+
+    <div class="row">
+        <div class="col-md-10">
+            <h2>${msg("editAccountHtmlTtile")}</h2>
+        </div>
+        <div class="col-md-2 subtitle">
+            <span class="subtitle"><span class="required">*</span> ${msg("requiredFields")}</span>
+        </div>
+    </div>
+
+    <form action="${url.accountUrl}" class="form-horizontal" method="post">
+
+        <input type="hidden" id="stateChecker" name="stateChecker" value="${stateChecker}">
+
+        <div class="form-group ${messagesPerField.printIfExists('username','has-error')}">
+            <div class="col-sm-2 col-md-2">
+                <label for="username" class="control-label">${msg("username")}</label> <#if realm.editUsernameAllowed><span class="required">*</span></#if>
+            </div>
+
+            <div class="col-sm-10 col-md-10">
+                <input type="text" class="form-control" id="username" name="username" <#if !realm.editUsernameAllowed>disabled="disabled"</#if> value="${(account.username!'')?html}"/>
+            </div>
+        </div>
+
+        <div class="form-group ${messagesPerField.printIfExists('email','has-error')}">
+            <div class="col-sm-2 col-md-2">
+            <label for="email" class="control-label">${msg("email")}</label> <span class="required">*</span>
+            </div>
+
+            <div class="col-sm-10 col-md-10">
+                <input type="text" class="form-control" id="email" name="email" autofocus value="${(account.email!'')?html}"/>
+            </div>
+        </div>
+
+        <div class="form-group ${messagesPerField.printIfExists('firstName','has-error')}">
+            <div class="col-sm-2 col-md-2">
+                <label for="firstName" class="control-label">${msg("firstName")}</label> <span class="required">*</span>
+            </div>
+
+            <div class="col-sm-10 col-md-10">
+                <input type="text" class="form-control" id="firstName" name="firstName" value="${(account.firstName!'')?html}"/>
+            </div>
+        </div>
+
+        <div class="form-group ${messagesPerField.printIfExists('lastName','has-error')}">
+            <div class="col-sm-2 col-md-2">
+                <label for="lastName" class="control-label">${msg("lastName")}</label> <span class="required">*</span>
+            </div>
+
+            <div class="col-sm-10 col-md-10">
+                <input type="text" class="form-control" id="lastName" name="lastName" value="${(account.lastName!'')?html}"/>
+            </div>
+        </div>
+
+        <div class="form-group">
+            <div class="col-sm-2 col-md-2">
+                <label for="user.attributes.street" class="control-label">${msg("street")}</label>
+            </div>
+
+            <div class="col-sm-10 col-md-10">
+                <input type="text" class="form-control" id="user.attributes.street" name="user.attributes.street" value="${(account.attributes.street!'')?html}"/>
+            </div>
+        </div>
+        <div class="form-group">
+            <div class="col-sm-2 col-md-2">
+                <label for="user.attributes.locality" class="control-label">${msg("locality")}</label>
+            </div>
+
+            <div class="col-sm-10 col-md-10">
+                <input type="text" class="form-control" id="user.attributes.locality" name="user.attributes.locality" value="${(account.attributes.locality!'')?html}"/>
+            </div>
+        </div>
+        <div class="form-group">
+            <div class="col-sm-2 col-md-2">
+                <label for="user.attributes.region" class="control-label">${msg("region")}</label>
+            </div>
+
+            <div class="col-sm-10 col-md-10">
+                <input type="text" class="form-control" id="user.attributes.region" name="user.attributes.region" value="${(account.attributes.region!'')?html}"/>
+            </div>
+        </div>
+        <div class="form-group">
+            <div class="col-sm-2 col-md-2">
+                <label for="user.attributes.postal_code" class="control-label">${msg("postal_code")}</label>
+            </div>
+
+            <div class="col-sm-10 col-md-10">
+                <input type="text" class="form-control" id="user.attributes.postal_code" name="user.attributes.postal_code" value="${(account.attributes.postal_code!'')?html}"/>
+            </div>
+        </div>
+        <div class="form-group">
+            <div class="col-sm-2 col-md-2">
+                <label for="user.attributes.country" class="control-label">${msg("country")}</label>
+            </div>
+
+            <div class="col-sm-10 col-md-10">
+                <input type="text" class="form-control" id="user.attributes.country" name="user.attributes.country" value="${(account.attributes.country!'')?html}"/>
+            </div>
+        </div>
+
+        <div class="form-group">
+            <div id="kc-form-buttons" class="col-md-offset-2 col-md-10 submit">
+                <div class="">
+                    <#if url.referrerURI??><a href="${url.referrerURI}">${msg("backToApplication")}/a></#if>
+                    <button type="submit" class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonLargeClass!}" name="submitAction" value="Save">${msg("doSave")}</button>
+                    <button type="submit" class="${properties.kcButtonClass!} ${properties.kcButtonDefaultClass!} ${properties.kcButtonLargeClass!}" name="submitAction" value="Cancel">${msg("doCancel")}</button>
+                </div>
+            </div>
+        </div>
+    </form>
+
+</@layout.mainLayout>
\ No newline at end of file
                diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/account/theme.properties b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/account/theme.properties
new file mode 100644
index 0000000..3e50437
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/account/theme.properties
@@ -0,0 +1,18 @@
+#
+# Copyright 2016 Red Hat, Inc. and/or its affiliates
+# and other contributors as indicated by the @author tags.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+parent=keycloak
\ No newline at end of file
                diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/admin/resources/partials/user-attributes.html b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/admin/resources/partials/user-attributes.html
new file mode 100755
index 0000000..af512de
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/admin/resources/partials/user-attributes.html
@@ -0,0 +1,72 @@
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
+    <ol class="breadcrumb">
+        <li><a href="#/realms/{{realm.realm}}/users">Users</a></li>
+        <li>{{user.username}}</li>
+    </ol>
+
+    <kc-tabs-user></kc-tabs-user>
+
+    <form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageUsers">
+        <div class="form-group clearfix block">
+            <label class="col-md-2 control-label" for="street">Street</label>
+            <div class="col-md-6">
+                <input ng-model="user.attributes.street" class="form-control" type="text" name="street" id="street" />
+            </div>
+            <kc-tooltip>Street address.</kc-tooltip>
+        </div>
+        <div class="form-group clearfix block">
+            <label class="col-md-2 control-label" for="locality">City or Locality</label>
+            <div class="col-md-6">
+                <input ng-model="user.attributes.locality" class="form-control" type="text" name="locality" id="locality" />
+            </div>
+            <kc-tooltip>City or locality.</kc-tooltip>
+        </div>
+        <div class="form-group clearfix block">
+            <label class="col-md-2 control-label" for="region">State, Province, or Region</label>
+            <div class="col-md-6">
+                <input ng-model="user.attributes.region" class="form-control" type="text" name="region" id="region" />
+            </div>
+            <kc-tooltip>State, province, prefecture, or region.</kc-tooltip>
+        </div>
+        <div class="form-group clearfix block">
+            <label class="col-md-2 control-label" for="postal_code">Zip or Postal code</label>
+            <div class="col-md-6">
+                <input ng-model="user.attributes.postal_code" class="form-control" type="text" name="postal_code" id="postal_code" />
+            </div>
+            <kc-tooltip>Zip code or postal code.</kc-tooltip>
+        </div>
+        <div class="form-group clearfix block">
+            <label class="col-md-2 control-label" for="country">Country</label>
+            <div class="col-md-6">
+                <input ng-model="user.attributes.country" class="form-control" type="text" name="country" id="country" />
+            </div>
+            <kc-tooltip>Country name.</kc-tooltip>
+        </div>
+
+        <div class="form-group" data-ng-show="access.manageUsers">
+            <div class="col-md-10 col-md-offset-2">
+                <button kc-save  data-ng-disabled="!changed">Save</button>
+                <button kc-reset data-ng-disabled="!changed">Cancel</button>
+            </div>
+        </div>
+    </form>
+</div>
+
+<kc-menu></kc-menu>
                diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/admin/theme.properties b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/admin/theme.properties
new file mode 100644
index 0000000..3e50437
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/admin/theme.properties
@@ -0,0 +1,18 @@
+#
+# Copyright 2016 Red Hat, Inc. and/or its affiliates
+# and other contributors as indicated by the @author tags.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+parent=keycloak
\ No newline at end of file
                diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/login/login-update-profile.ftl b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/login/login-update-profile.ftl
new file mode 100755
index 0000000..e02a340
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/login/login-update-profile.ftl
@@ -0,0 +1,95 @@
+<#import "template.ftl" as layout>
+<@layout.registrationLayout; section>
+    <#if section = "title">
+        ${msg("loginProfileTitle")}
+    <#elseif section = "header">
+        ${msg("loginProfileTitle")}
+    <#elseif section = "form">
+        <form id="kc-update-profile-form" class="${properties.kcFormClass!}" action="${url.loginAction}" method="post">
+            <div class="${properties.kcFormGroupClass!} ${messagesPerField.printIfExists('email',properties.kcFormGroupErrorClass!)}">
+                <div class="${properties.kcLabelWrapperClass!}">
+                    <label for="email" class="${properties.kcLabelClass!}">${msg("email")}</label>
+                </div>
+                <div class="${properties.kcInputWrapperClass!}">
+                    <input type="text" id="email" name="email" value="${(user.email!'')?html}" class="${properties.kcInputClass!}" />
+                </div>
+            </div>
+
+            <div class="${properties.kcFormGroupClass!} ${messagesPerField.printIfExists('firstName',properties.kcFormGroupErrorClass!)}">
+                <div class="${properties.kcLabelWrapperClass!}">
+                    <label for="firstName" class="${properties.kcLabelClass!}">${msg("firstName")}</label>
+                </div>
+                <div class="${properties.kcInputWrapperClass!}">
+                    <input type="text" id="firstName" name="firstName" value="${(user.firstName!'')?html}" class="${properties.kcInputClass!}" />
+                </div>
+            </div>
+
+            <div class="${properties.kcFormGroupClass!} ${messagesPerField.printIfExists('lastName',properties.kcFormGroupErrorClass!)}">
+                <div class="${properties.kcLabelWrapperClass!}">
+                    <label for="lastName" class="${properties.kcLabelClass!}">${msg("lastName")}</label>
+                </div>
+                <div class="${properties.kcInputWrapperClass!}">
+                    <input type="text" id="lastName" name="lastName" value="${(user.lastName!'')?html}" class="${properties.kcInputClass!}" />
+                </div>
+            </div>
+            
+            <div class="form-group">
+                <div class="${properties.kcLabelWrapperClass!}">
+                    <label for="user.attributes.street" class="${properties.kcLabelClass!}">${msg("street")}</label>
+                </div>
+
+                <div class="${properties.kcInputWrapperClass!}">
+                    <input type="text" class="${properties.kcInputClass!}"  id="user.attributes.street" name="user.attributes.street" value="${(user.attributes.street!'')?html}"/>
+                </div>
+            </div>
+            <div class="form-group">
+                <div class="${properties.kcLabelWrapperClass!}">
+                    <label for="user.attributes.locality" class="${properties.kcLabelClass!}">${msg("locality")}</label>
+                </div>
+
+                <div class="${properties.kcInputWrapperClass!}">
+                    <input type="text" class="${properties.kcInputClass!}"  id="user.attributes.locality" name="user.attributes.locality" value="${(user.attributes.locality!'')?html}"/>
+                </div>
+            </div>
+            <div class="form-group">
+                <div class="${properties.kcLabelWrapperClass!}">
+                    <label for="user.attributes.region" class="${properties.kcLabelClass!}">${msg("region")}</label>
+                </div>
+
+                <div class="${properties.kcInputWrapperClass!}">
+                    <input type="text" class="${properties.kcInputClass!}"  id="user.attributes.region" name="user.attributes.region" value="${(user.attributes.region!'')?html}"/>
+                </div>
+            </div>
+            <div class="form-group">
+                <div class="${properties.kcLabelWrapperClass!}">
+                    <label for="user.attributes.postal_code" class="${properties.kcLabelClass!}">${msg("postal_code")}</label>
+                </div>
+
+                <div class="${properties.kcInputWrapperClass!}">
+                    <input type="text" class="${properties.kcInputClass!}"  id="user.attributes.postal_code" name="user.attributes.postal_code" value="${(user.attributes.postal_code!'')?html}"/>
+                </div>
+            </div>
+            <div class="form-group">
+                <div class="${properties.kcLabelWrapperClass!}">
+                    <label for="user.attributes.country" class="${properties.kcLabelClass!}">${msg("country")}</label>
+                </div>
+
+                <div class="${properties.kcInputWrapperClass!}">
+                    <input type="text" class="${properties.kcInputClass!}"  id="user.attributes.country" name="user.attributes.country" value="${(user.attributes.country!'')?html}"/>
+                </div>
+            </div>
+            
+
+            <div class="${properties.kcFormGroupClass!}">
+                <div id="kc-form-options" class="${properties.kcFormOptionsClass!}">
+                    <div class="${properties.kcFormOptionsWrapperClass!}">
+                    </div>
+                </div>
+
+                <div id="kc-form-buttons" class="${properties.kcFormButtonsClass!}">
+                    <input class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonLargeClass!}" type="submit" value="${msg("doSubmit")}" />
+                </div>
+            </div>
+        </form>
+    </#if>
+</@layout.registrationLayout>
\ No newline at end of file
                diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/login/register.ftl b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/login/register.ftl
new file mode 100755
index 0000000..3247305
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/login/register.ftl
@@ -0,0 +1,131 @@
+<#import "template.ftl" as layout>
+<@layout.registrationLayout; section>
+    <#if section = "title">
+        ${msg("registerWithTitle",(realm.name!''))}
+    <#elseif section = "header">
+         ${msg("registerWithTitleHtml",(realm.name!''))}
+    <#elseif section = "form">
+        <form id="kc-register-form" class="${properties.kcFormClass!}" action="${url.registrationAction}" method="post">
+          <#if !realm.registrationEmailAsUsername>
+            <div class="${properties.kcFormGroupClass!} ${messagesPerField.printIfExists('username',properties.kcFormGroupErrorClass!)}">
+                <div class="${properties.kcLabelWrapperClass!}">
+                    <label for="username" class="${properties.kcLabelClass!}">${msg("username")}</label>
+                </div>
+                <div class="${properties.kcInputWrapperClass!}">
+                    <input type="text" id="username" class="${properties.kcInputClass!}" name="username" value="${(register.formData.username!'')?html}" />
+                </div>
+            </div>
+          </#if>
+            <div class="${properties.kcFormGroupClass!} ${messagesPerField.printIfExists('firstName',properties.kcFormGroupErrorClass!)}">
+                <div class="${properties.kcLabelWrapperClass!}">
+                    <label for="firstName" class="${properties.kcLabelClass!}">${msg("firstName")}</label>
+                </div>
+                <div class="${properties.kcInputWrapperClass!}">
+                    <input type="text" id="firstName" class="${properties.kcInputClass!}" name="firstName" value="${(register.formData.firstName!'')?html}" />
+                </div>
+            </div>
+
+            <div class="${properties.kcFormGroupClass!} ${messagesPerField.printIfExists('lastName',properties.kcFormGroupErrorClass!)}">
+                <div class="${properties.kcLabelWrapperClass!}">
+                    <label for="lastName" class="${properties.kcLabelClass!}">${msg("lastName")}</label>
+                </div>
+                <div class="${properties.kcInputWrapperClass!}">
+                    <input type="text" id="lastName" class="${properties.kcInputClass!}" name="lastName" value="${(register.formData.lastName!'')?html}" />
+                </div>
+            </div>
+
+            <div class="${properties.kcFormGroupClass!} ${messagesPerField.printIfExists('email',properties.kcFormGroupErrorClass!)}">
+                <div class="${properties.kcLabelWrapperClass!}">
+                    <label for="email" class="${properties.kcLabelClass!}">${msg("email")}</label>
+                </div>
+                <div class="${properties.kcInputWrapperClass!}">
+                    <input type="text" id="email" class="${properties.kcInputClass!}" name="email" value="${(register.formData.email!'')?html}" />
+                </div>
+            </div>
+
+            <#if passwordRequired>
+            <div class="${properties.kcFormGroupClass!} ${messagesPerField.printIfExists('password',properties.kcFormGroupErrorClass!)}">
+                <div class="${properties.kcLabelWrapperClass!}">
+                    <label for="password" class="${properties.kcLabelClass!}">${msg("password")}</label>
+                </div>
+                <div class="${properties.kcInputWrapperClass!}">
+                    <input type="password" id="password" class="${properties.kcInputClass!}" name="password" />
+                </div>
+            </div>
+
+            <div class="${properties.kcFormGroupClass!} ${messagesPerField.printIfExists('password-confirm',properties.kcFormGroupErrorClass!)}">
+                <div class="${properties.kcLabelWrapperClass!}">
+                    <label for="password-confirm" class="${properties.kcLabelClass!}">${msg("passwordConfirm")}</label>
+                </div>
+                <div class="${properties.kcInputWrapperClass!}">
+                    <input type="password" id="password-confirm" class="${properties.kcInputClass!}" name="password-confirm" />
+                </div>
+            </div>
+            </#if>
+            <div class="form-group">
+                <div class="${properties.kcLabelWrapperClass!}">
+                    <label for="user.attributes.street" class="${properties.kcLabelClass!}">${msg("street")}</label>
+                </div>
+
+                <div class="${properties.kcInputWrapperClass!}">
+                    <input type="text" class="${properties.kcInputClass!}"  id="user.attributes.street" name="user.attributes.street" value="${(register.formData['user.attributes.street']!'')?html}"/>
+                </div>
+            </div>
+            <div class="form-group">
+                <div class="${properties.kcLabelWrapperClass!}">
+                    <label for="user.attributes.locality" class="${properties.kcLabelClass!}">${msg("locality")}</label>
+                </div>
+
+                <div class="${properties.kcInputWrapperClass!}">
+                    <input type="text" class="${properties.kcInputClass!}"  id="user.attributes.locality" name="user.attributes.locality" value="${(register.formData['user.attributes.locality']!'')?html}"/>
+                </div>
+            </div>
+            <div class="form-group">
+                <div class="${properties.kcLabelWrapperClass!}">
+                    <label for="user.attributes.region" class="${properties.kcLabelClass!}">${msg("region")}</label>
+                </div>
+
+                <div class="${properties.kcInputWrapperClass!}">
+                    <input type="text" class="${properties.kcInputClass!}"  id="user.attributes.region" name="user.attributes.region" value="${(register.formData['user.attributes.region']!'')?html}"/>
+                </div>
+            </div>
+            <div class="form-group">
+                <div class="${properties.kcLabelWrapperClass!}">
+                    <label for="user.attributes.postal_code" class="${properties.kcLabelClass!}">${msg("postal_code")}</label>
+                </div>
+
+                <div class="${properties.kcInputWrapperClass!}">
+                    <input type="text" class="${properties.kcInputClass!}"  id="user.attributes.postal_code" name="user.attributes.postal_code" value="${(register.formData['user.attributes.postal_code']!'')?html}"/>
+                </div>
+            </div>
+            <div class="form-group">
+                <div class="${properties.kcLabelWrapperClass!}">
+                    <label for="user.attributes.country" class="${properties.kcLabelClass!}">${msg("country")}</label>
+                </div>
+
+                <div class="${properties.kcInputWrapperClass!}">
+                    <input type="text" class="${properties.kcInputClass!}"  id="user.attributes.country" name="user.attributes.country" value="${(register.formData['user.attributes.country']!'')?html}"/>
+                </div>
+            </div>
+            <#if recaptchaRequired??>
+            <div class="form-group">
+                <div class="${properties.kcInputWrapperClass!}">
+                    <div class="g-recaptcha" data-size="compact" data-sitekey="${recaptchaSiteKey}"></div>
+                </div>
+            </div>
+            </#if>
+
+            <div class="${properties.kcFormGroupClass!}">
+                <div id="kc-form-options" class="${properties.kcFormOptionsClass!}">
+                    <div class="${properties.kcFormOptionsWrapperClass!}">
+                        <span><a href="${url.loginUrl}">${msg("backToLogin")}</a></span>
+                    </div>
+                </div>
+
+                <div id="kc-form-buttons" class="${properties.kcFormButtonsClass!}">
+                    <input class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonLargeClass!}" type="submit" value="${msg("doRegister")}"/>
+                </div>
+            </div>
+        </form>
+    </#if>
+</@layout.registrationLayout>
\ No newline at end of file
                diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/login/theme.properties b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/login/theme.properties
new file mode 100644
index 0000000..3e50437
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/login/theme.properties
@@ -0,0 +1,18 @@
+#
+# Copyright 2016 Red Hat, Inc. and/or its affiliates
+# and other contributors as indicated by the @author tags.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+parent=keycloak
\ No newline at end of file
                diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/AccountUpdateProfilePage.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/AccountUpdateProfilePage.java
index 2159c2f..2a77847 100755
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/AccountUpdateProfilePage.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/AccountUpdateProfilePage.java
@@ -17,7 +17,9 @@
 
 package org.keycloak.testsuite.pages;
 
+import org.keycloak.models.Constants;
 import org.keycloak.services.resources.RealmsResource;
+import org.openqa.selenium.By;
 import org.openqa.selenium.WebElement;
 import org.openqa.selenium.support.FindBy;
 
@@ -96,6 +98,14 @@ public class AccountUpdateProfilePage extends AbstractAccountPage {
         submitButton.click();
     }
 
+    public void updateAttribute(String attrName, String attrValue) {
+        WebElement attrElement = findAttributeInputElement(attrName);
+        attrElement.clear();
+        attrElement.sendKeys(attrValue);
+        submitButton.click();
+    }
+
+
     public void clickCancel() {
         cancelButton.click();
     }
@@ -117,6 +127,11 @@ public class AccountUpdateProfilePage extends AbstractAccountPage {
         return emailInput.getAttribute("value");
     }
 
+    public String getAttribute(String attrName) {
+        WebElement attrElement = findAttributeInputElement(attrName);
+        return attrElement.getAttribute("value");
+    }
+
     public boolean isCurrent() {
         return driver.getTitle().contains("Account Management") && driver.getPageSource().contains("Edit Account");
     }
@@ -140,4 +155,9 @@ public class AccountUpdateProfilePage extends AbstractAccountPage {
     public boolean isPasswordUpdateSupported() {
         return driver.getPageSource().contains(getPath() + "/password");
     }
+
+    private WebElement findAttributeInputElement(String attrName) {
+        String attrId = Constants.USER_ATTRIBUTES_PREFIX + attrName;
+        return driver.findElement(By.id(attrId));
+    }
 }
                diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/custom/CustomThemeTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/custom/CustomThemeTest.java
new file mode 100644
index 0000000..810d9c2
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/custom/CustomThemeTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.account.custom;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.keycloak.events.Details;
+import org.keycloak.events.EventType;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.testsuite.AssertEvents;
+import org.keycloak.testsuite.TestRealmKeycloakTest;
+import org.keycloak.testsuite.account.AccountTest;
+import org.keycloak.testsuite.pages.AccountUpdateProfilePage;
+import org.keycloak.testsuite.pages.LoginPage;
+import org.keycloak.testsuite.util.RealmBuilder;
+import org.keycloak.testsuite.util.UserBuilder;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class CustomThemeTest extends TestRealmKeycloakTest {
+
+    @Override
+    public void configureTestRealm(RealmRepresentation testRealm) {
+        testRealm.setAccountTheme("address");
+
+        UserRepresentation user2 = UserBuilder.create()
+                .enabled(true)
+                .username("test-user-no-access@localhost")
+                .email("test-user-no-access@localhost")
+                .password("password")
+                .build();
+
+        RealmBuilder.edit(testRealm)
+                .user(user2);
+    }
+
+    @Rule
+    public AssertEvents events = new AssertEvents(this);
+
+    @Page
+    protected LoginPage loginPage;
+
+    @Page
+    protected AccountUpdateProfilePage profilePage;
+
+    // KEYCLOAK-3494
+    @Test
+    public void changeProfile() throws Exception {
+        profilePage.open();
+        loginPage.login("test-user@localhost", "password");
+
+        events.expectLogin().client("account").detail(Details.REDIRECT_URI, AccountTest.ACCOUNT_REDIRECT).assertEvent();
+
+        Assert.assertEquals("test-user@localhost", profilePage.getEmail());
+        Assert.assertEquals("", profilePage.getAttribute("street"));
+
+        profilePage.updateAttribute("street", "Elm 1");
+        Assert.assertEquals("Elm 1", profilePage.getAttribute("street"));
+
+        profilePage.updateAttribute("street", "Elm 2");
+        Assert.assertEquals("Elm 2", profilePage.getAttribute("street"));
+
+        events.expectAccount(EventType.UPDATE_PROFILE).assertEvent();
+    }
+
+
+}
                diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserFederationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserFederationTest.java
index 8cef8a1..7a939c3 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserFederationTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserFederationTest.java
@@ -51,7 +51,7 @@ public class UserFederationTest extends AbstractAdminTest {
     @Test
     public void testProviderFactories() {
         List<UserFederationProviderFactoryRepresentation> providerFactories = userFederation().getProviderFactories();
-        Assert.assertNames(providerFactories, "ldap", "kerberos", "dummy", "dummy-configurable");
+        Assert.assertNames(providerFactories, "ldap", "kerberos", "dummy", "dummy-configurable", "sssd");
 
         // Builtin provider without properties
         UserFederationProviderFactoryRepresentation ldapProvider = userFederation().getProviderFactory("ldap");