summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon McVittie <simon.mcvittie@collabora.co.uk>2010-11-23 20:40:48 +0000
committerSimon McVittie <simon.mcvittie@collabora.co.uk>2010-11-23 20:40:48 +0000
commit9214b4f5006349a7d71907cb87ae40a6f959504f (patch)
tree58eea866eb370c938f95eec11fba66e900a3f0b8
parent477b7ab10d8a140f75ee8bfc0e99a71bc282f0af (diff)
Update SASL to current spec master
-rw-r--r--extensions/Channel_Interface_SASL_Authentication.xml138
-rw-r--r--extensions/Channel_Interface_Securable.xml80
-rw-r--r--extensions/Channel_Type_Server_Authentication.xml5
-rw-r--r--extensions/Makefile.am1
-rw-r--r--extensions/all.xml1
-rw-r--r--src/server-sasl-channel.c62
6 files changed, 182 insertions, 105 deletions
diff --git a/extensions/Channel_Interface_SASL_Authentication.xml b/extensions/Channel_Interface_SASL_Authentication.xml
index bb25a6b9..355b7ce3 100644
--- a/extensions/Channel_Interface_SASL_Authentication.xml
+++ b/extensions/Channel_Interface_SASL_Authentication.xml
@@ -29,7 +29,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.</
namespace="ofdT.Channel.Type">ServerAuthentication.DRAFT2</tp:dbus-ref>
channel, it represents authentication with the server. In future,
it could also be used to authenticate with secondary services,
- or even to authenticate end-to-end connections with contacts.</p>
+ or even to authenticate end-to-end connections with contacts. As a result,
+ this interface does not REQUIRE <tp:dbus-ref namespace="ofdT.Channel.Type"
+ >ServerAuthentication.DRAFT2</tp:dbus-ref> to allow for a potential future
+ Channel.Type.PeerAuthentication interface.</p>
<p>In any protocol that requires a password, the connection manager can
use this channel to let a user interface carry out a simple SASL-like
@@ -153,46 +156,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.</
</tp:docstring>
</property>
- <property name="Encrypted"
- tp:name-for-bindings="Encrypted" type="b"
- access="read" tp:immutable="yes">
- <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
- <p>True if this authentication process occurs over an encrypted
- connection. This <strong>does not</strong> imply that steps have
- been taken to avoid man-in-the-middle attacks.</p>
-
- <tp:rationale>
- <p>For future support for <a
- href="http://tools.ietf.org/html/rfc5056">RFC 5056 Channel
- Binding</a> it is desirable to be able to use some SASL
- mechanisms over an encrypted connection to an unverified peer,
- which can prove that it is the desired destination during
- the SASL negotiation.</p>
- </tp:rationale>
-
- <p>Clients MAY use the combination of this property and
- <tp:member-ref>Verified</tp:member-ref> to decide whether the
- <code>PLAIN</code> mechanism is acceptable, for instance.</p>
- </tp:docstring>
- </property>
-
- <property name="Verified"
- tp:name-for-bindings="Verified" type="b"
- access="read" tp:immutable="yes">
- <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
- <p>True if this authentication process occurs over a connection
- that is protected against tampering, and has been verified to
- be with the desired destination: for instance, one where TLS
- was previously negotiated, and the TLS certificate has been
- verified against a configured certificate authority or
- accepted by the user.</p>
-
- <p>Clients MAY use the combination of this property and
- <tp:member-ref>Encrypted</tp:member-ref> to decide whether the
- <code>PLAIN</code> mechanism is acceptable, for instance.</p>
- </tp:docstring>
- </property>
-
<property type="u" tp:type="SASL_Status" access="read"
name="SASLStatus" tp:name-for-bindings="SASL_Status">
<tp:docstring xmlns="http://www.w3.org/1999/xhtml">
@@ -311,6 +274,69 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.</
</tp:docstring>
</property>
+ <property name="DefaultUsername"
+ tp:name-for-bindings="Default_Username"
+ type="s" access="read" tp:immutable="yes">
+ <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
+ <p>The default username for use with SASL mechanisms that deal
+ with a "simple username" (as defined in <a
+ href="http://tools.ietf.org/html/rfc4422">RFC 4422</a>). If
+ such a SASL mechanism is in use, clients SHOULD default to
+ using the DefaultUsername; also, if the client uses
+ the DefaultUsername, it SHOULD assume that the authorization
+ identity <tp:member-ref>AuthorizationIdentity</tp:member-ref>
+ will be derived from it by the server.</p>
+
+ <tp:rationale>
+ <p>In XMPP, <a href="http://trac.tools.ietf.org/wg/xmpp/trac/ticket/49">
+ servers typically expect</a> "user@example.com" to
+ authenticate with username "user"; this was a SHOULD in <a
+ href="http://tools.ietf.org/html/rfc3920">RFC 3920</a>.</p>
+
+ <p><a
+ href="http://tools.ietf.org/html/draft-ietf-xmpp-3920bis-19">3920bis</a>
+ weakens that SHOULD to "in the absence of local information
+ provided by the server, an XMPP client SHOULD assume that
+ the authentication identity for such a SASL mechanism is the
+ combination of a user name and password, where the simple
+ user name is the localpart of the user's JID".</p>
+ </tp:rationale>
+
+ <p>For example, in the simple case, if the user connects with
+ <tp:dbus-ref
+ namespace="ofdT.ConnectionManager">RequestConnection</tp:dbus-ref>({
+ account: "<tt>user@example.com</tt>" }) and use PLAIN with
+ password "password", he or she should authenticate like so:
+ "<tt>\0user\0password</tt>" and the channel will look like
+ this:</p>
+
+<blockquote><pre>{ "...<tp:member-ref>DefaultUsername</tp:member-ref>": "user",
+ "...<tp:member-ref>AuthorizationIdentity</tp:member-ref>": "user@example.com }
+</pre></blockquote>
+
+ <p>In the complex case, if the same user is using his or her
+ sysadmin powers to log in as the "announcements" role address,
+ he or she would connect with <tp:dbus-ref
+ namespace="ofdT.ConnectionManager">RequestConnection</tp:dbus-ref>({
+ account: "<tt>announcements@example.com</tt>" }) and the SASL
+ channel would look like this:</p>
+
+<blockquote><pre>{ "...<tp:member-ref>DefaultUsername</tp:member-ref>": "announcements",
+ "...<tp:member-ref>AuthorizationIdentity</tp:member-ref>": "announcements@example.com }
+</pre></blockquote>
+
+ <p>A sufficiently elaborate UI could give the opportunity
+ to override the username from "announcements" to "user".
+ The user's simple username is still "user", and the password is
+ still "password", but this time he or she is trying to authorize
+ to act as <tt>announcements@example.com</tt>, so the UI would
+ have to perform SASL PLAIN with this string:
+ "<tt>announcements@example.com\0user\0password</tt>", where
+ "announcements@example.com" is the
+ <tp:member-ref>AuthorizationIdentity</tp:member-ref>.</p>
+ </tp:docstring>
+ </property>
+
<property name="DefaultRealm" tp:name-for-bindings="Default_Realm"
type="s" access="read" tp:immutable="yes">
<tp:docstring xmlns="http://www.w3.org/1999/xhtml">
@@ -334,23 +360,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.</
</tp:docstring>
</property>
- <property name="SASLContext" tp:name-for-bindings="SASL_Context"
- type="a{sv}" tp:type="String_Variant_Map" access="read"
- tp:immutable="yes">
- <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
- <p>Additional protocol- or mechanism-specific context for the
- authentication. Only one well-known key is currently defined:</p>
-
- <dl>
- <dt>jabber-stream-id (string)</dt>
- <dd>The <code>id</code> attribute of the XMPP <code>stream</code>
- element, as used in <a
- href="http://xmpp.org/extensions/xep-0078.html">the digest
- mechanism historically used in Jabber</a>.</dd>
- </dl>
- </tp:docstring>
- </property>
-
<method name="StartMechanism" tp:name-for-bindings="Start_Mechanism">
<arg direction="in" name="Mechanism" type="s" tp:type="SASL_Mechanism">
<tp:docstring>
@@ -527,10 +536,19 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.</
<p>If the current status is SASL_Status_Server_Failed or
SASL_Status_Client_Failed, this method returns successfully, but has
- no further effect. Otherwise, it changes the channel's state to
+ no further effect. If the current status is SASL_Status_Succeeded
+ or SASL_Status_Client_Accepted then NotAvailable is raised.
+ Otherwise, it changes the channel's state to
SASL_Status_Client_Failed, with an appropriate error name and
reason code.</p>
</tp:docstring>
+ <tp:possible-errors>
+ <tp:error name="org.freedesktop.Telepathy.Error.NotAvailable">
+ <tp:docstring>
+ The current state is either Succeeded or Client_Accepted.
+ </tp:docstring>
+ </tp:error>
+ </tp:possible-errors>
</method>
<signal name="SASLStatusChanged" tp:name-for-bindings="SASL_Status_Changed">
@@ -590,7 +608,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.</
</tp:enumvalue>
</tp:enum>
- <tp:enum name="SASL_Status" type="u">
+ <tp:enum name="SASL_Status" type="u" plural="SASL_Statuses">
<tp:enumvalue suffix="Not_Started" value="0">
<tp:docstring>
The initial state. The Handler SHOULD either
diff --git a/extensions/Channel_Interface_Securable.xml b/extensions/Channel_Interface_Securable.xml
new file mode 100644
index 00000000..fbf882b2
--- /dev/null
+++ b/extensions/Channel_Interface_Securable.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0" ?>
+<node name="/Channel_Interface_Securable"
+ xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0">
+ <tp:copyright>Copyright (C) 2010 Collabora Ltd.</tp:copyright>
+
+ <tp:license xmlns="http://www.w3.org/1999/xhtml">
+ <p>This 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.</p>
+
+ <p>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
+ Lesser General Public License for more details.</p>
+
+ <p>You should have received a copy of the GNU Lesser 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.</p>
+ </tp:license>
+
+ <interface
+ name="org.freedesktop.Telepathy.Channel.Interface.Securable.DRAFT"
+ tp:causes-havoc="experimental">
+ <tp:added version="0.21.UNRELEASED">as a draft</tp:added>
+ <tp:requires interface="org.freedesktop.Telepathy.Channel"/>
+
+ <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
+ <p>This interface exists to expose security information about
+ <tp:dbus-ref namespace="ofdT">Channel</tp:dbus-ref>s. The two
+ properties are sometimes immutable and can be used to make
+ decisions on how cautious to be about transferring sensitive
+ data. The special case of <tp:dbus-ref
+ namespace="ofdT.Channel.Type">ServerAuthentication.DRAFT2</tp:dbus-ref>
+ channels is one example of where the two properties are
+ immutable.</p>
+
+ <p>For example, clients MAY use these properties to decide
+ whether the <code>PLAIN</code> mechanism is acceptable for a
+ <tp:dbus-ref
+ namespace="ofdT.Channel.Interface">SASLAuthentication.DRAFT2</tp:dbus-ref>
+ channel.</p>
+ </tp:docstring>
+
+ <property name="Encrypted"
+ tp:name-for-bindings="Encrypted" type="b"
+ access="read" tp:immutable="sometimes">
+ <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
+ <p>True if this channel occurs over an encrypted
+ connection. This <strong>does not</strong> imply that steps
+ have been taken to avoid man-in-the-middle attacks.</p>
+
+ <tp:rationale>
+ <p>For future support for <a
+ href="http://tools.ietf.org/html/rfc5056">RFC 5056 Channel
+ Binding</a> it is desirable to be able to use some SASL
+ mechanisms over an encrypted connection to an unverified peer,
+ which can prove that it is the desired destination during
+ the SASL negotiation.</p>
+ </tp:rationale>
+ </tp:docstring>
+ </property>
+
+ <property name="Verified"
+ tp:name-for-bindings="Verified" type="b"
+ access="read" tp:immutable="sometimes">
+ <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
+ <p>True if this channel occurs over a connection that is
+ protected against tampering, and has been verified to be with
+ the desired destination: for instance, one where TLS was
+ previously negotiated, and the TLS certificate has been
+ verified against a configured certificate authority or
+ accepted by the user.</p>
+ </tp:docstring>
+ </property>
+
+ </interface>
+</node>
+<!-- vim:set sw=2 sts=2 et ft=xml: -->
diff --git a/extensions/Channel_Type_Server_Authentication.xml b/extensions/Channel_Type_Server_Authentication.xml
index ae5fd061..e394b4e3 100644
--- a/extensions/Channel_Type_Server_Authentication.xml
+++ b/extensions/Channel_Type_Server_Authentication.xml
@@ -91,6 +91,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.</
namespace="ofdT">ChannelDispatcher</tp:dbus-ref> will close the
channel if it cannot find a handler.</p>
</tp:rationale>
+
+ <p>When the connection is done with the channel and it is no
+ longer needed, it is left open until either the connection state
+ turns to DISCONNECTED or the handler closes the channel. The
+ channel SHOULD NOT close itself once finished with.</p>
</tp:docstring>
<property name="AuthenticationMethod"
diff --git a/extensions/Makefile.am b/extensions/Makefile.am
index f217b668..00ae717f 100644
--- a/extensions/Makefile.am
+++ b/extensions/Makefile.am
@@ -18,6 +18,7 @@ EXTRA_DIST = \
OLPC_Activity_Properties.xml \
OLPC_Buddy_Info.xml \
Channel_Interface_SASL_Authentication.xml \
+ Channel_Interface_Securable.xml \
Channel_Type_Server_Authentication.xml
noinst_LTLIBRARIES = libgabble-extensions.la
diff --git a/extensions/all.xml b/extensions/all.xml
index 00d3f02c..5eeedb81 100644
--- a/extensions/all.xml
+++ b/extensions/all.xml
@@ -54,6 +54,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA</p>
<xi:include href="Channel_Type_Server_Authentication.xml" />
<xi:include href="Channel_Interface_SASL_Authentication.xml" />
+<xi:include href="Channel_Interface_Securable.xml" />
<tp:generic-types>
<tp:external-type name="Contact_Handle" type="u"
diff --git a/src/server-sasl-channel.c b/src/server-sasl-channel.c
index aae8259b..e6527c70 100644
--- a/src/server-sasl-channel.c
+++ b/src/server-sasl-channel.c
@@ -61,21 +61,21 @@ G_DEFINE_TYPE_WITH_CODE (GabbleServerSaslChannel, gabble_server_sasl_channel,
G_IMPLEMENT_INTERFACE (
GABBLE_TYPE_SVC_CHANNEL_TYPE_SERVER_AUTHENTICATION,
NULL);
+ G_IMPLEMENT_INTERFACE (GABBLE_TYPE_SVC_CHANNEL_INTERFACE_SECURABLE, NULL);
G_IMPLEMENT_INTERFACE (
GABBLE_TYPE_SVC_CHANNEL_INTERFACE_SASL_AUTHENTICATION,
sasl_auth_iface_init));
static const gchar *gabble_server_sasl_channel_interfaces[] = {
GABBLE_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION,
+ GABBLE_IFACE_CHANNEL_INTERFACE_SECURABLE,
NULL
};
enum
{
- PROP_SESSION_ID = 1,
-
/* server authentication channel */
- PROP_AUTH_METHOD,
+ PROP_AUTH_METHOD = 1,
/* sasl authentication channel */
PROP_AVAILABLE_MECHANISMS,
@@ -88,7 +88,6 @@ enum
PROP_AUTHORIZATION_IDENTITY,
PROP_DEFAULT_USERNAME,
PROP_DEFAULT_REALM,
- PROP_SASL_CONTEXT,
LAST_PROPERTY,
};
@@ -100,7 +99,6 @@ struct _GabbleServerSaslChannelPrivate
/* Immutable SASL properties */
GStrv available_mechanisms;
gboolean secure;
- GHashTable *sasl_context;
/* Mutable SASL properties */
GabbleSASLStatus sasl_status;
@@ -118,8 +116,6 @@ gabble_server_sasl_channel_init (GabbleServerSaslChannel *self)
self->priv = priv;
- priv->sasl_context = tp_asv_new (NULL, NULL);
-
priv->sasl_status = GABBLE_SASL_STATUS_NOT_STARTED;
priv->sasl_error = NULL;
priv->sasl_error_details = tp_asv_new (NULL, NULL);
@@ -139,14 +135,13 @@ gabble_server_sasl_channel_fill_immutable_properties (TpBaseChannel *channel,
"AvailableMechanisms",
GABBLE_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION, "HasInitialData",
GABBLE_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION, "CanTryAgain",
- GABBLE_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION, "Encrypted",
- GABBLE_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION, "Verified",
GABBLE_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION,
"AuthorizationIdentity",
GABBLE_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION, "DefaultRealm",
- /* FIXME: GABBLE_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION,
- "DefaultUsername", */
- GABBLE_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION, "SASLContext",
+ GABBLE_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION,
+ "DefaultUsername",
+ GABBLE_IFACE_CHANNEL_INTERFACE_SECURABLE, "Encrypted",
+ GABBLE_IFACE_CHANNEL_INTERFACE_SECURABLE, "Verified",
NULL);
}
@@ -178,9 +173,6 @@ gabble_server_sasl_channel_get_property (GObject *object,
case PROP_SASL_ERROR_DETAILS:
g_value_set_boxed (value, priv->sasl_error_details);
break;
- case PROP_SASL_CONTEXT:
- g_value_set_boxed (value, priv->sasl_context);
- break;
case PROP_AUTH_METHOD:
g_value_set_static_string (value,
GABBLE_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION);
@@ -233,10 +225,6 @@ gabble_server_sasl_channel_get_property (GObject *object,
G_OBJECT (tp_base_channel_get_connection (channel)), "username",
value);
break;
- case PROP_SESSION_ID:
- g_value_set_string (value,
- tp_asv_get_string (priv->sasl_context, "jabber-stream-id"));
- break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -262,11 +250,6 @@ gabble_server_sasl_channel_set_property (GObject *object,
priv->available_mechanisms = g_value_dup_boxed (value);
break;
- case PROP_SESSION_ID:
- g_hash_table_insert (priv->sasl_context, "jabber-stream-id",
- tp_g_value_slice_dup (value));
- break;
-
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -284,7 +267,6 @@ gabble_server_sasl_channel_finalize (GObject *object)
g_assert (priv->result == NULL);
g_strfreev (priv->available_mechanisms);
- g_hash_table_unref (priv->sasl_context);
g_free (priv->sasl_error);
g_hash_table_unref (priv->sasl_error_details);
@@ -311,8 +293,10 @@ gabble_server_sasl_channel_class_init (GabbleServerSaslChannelClass *klass)
{ "SASLErrorDetails", "sasl-error-details", NULL },
{ "AuthorizationIdentity", "authorization-identity", NULL },
{ "DefaultRealm", "default-realm", NULL },
- /* FIXME: { "DefaultUsername", "default-username", NULL }, */
- { "SASLContext", "sasl-context", NULL },
+ { "DefaultUsername", "default-username", NULL },
+ { NULL }
+ };
+ static TpDBusPropertiesMixinPropImpl securable_props[] = {
/* For the moment we only have a unified "secure" property, which
* implies we're both encrypted and verified */
{ "Encrypted", "secure", NULL },
@@ -330,6 +314,11 @@ gabble_server_sasl_channel_class_init (GabbleServerSaslChannelClass *klass)
NULL,
sasl_auth_props,
},
+ { GABBLE_IFACE_CHANNEL_INTERFACE_SECURABLE,
+ tp_dbus_properties_mixin_getter_gobject_properties,
+ NULL,
+ securable_props,
+ },
{ NULL }
};
GObjectClass *object_class = G_OBJECT_CLASS (klass);
@@ -352,13 +341,6 @@ gabble_server_sasl_channel_class_init (GabbleServerSaslChannelClass *klass)
gabble_server_sasl_channel_get_object_path_suffix;
channel_class->close = gabble_server_sasl_channel_close;
- param_spec = g_param_spec_boxed ("sasl-context", "SASLContext",
- "Extra context for doing SASL",
- TP_HASH_TYPE_STRING_VARIANT_MAP,
- G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
- g_object_class_install_property (object_class, PROP_SASL_CONTEXT,
- param_spec);
-
param_spec = g_param_spec_string ("auth-method",
"Authentication method",
"Method of authentication (D-Bus interface)",
@@ -367,14 +349,6 @@ gabble_server_sasl_channel_class_init (GabbleServerSaslChannelClass *klass)
g_object_class_install_property (object_class, PROP_AUTH_METHOD,
param_spec);
- param_spec = g_param_spec_string ("session-id",
- "Session ID",
- "Jabber <stream> id attribute",
- NULL,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
- g_object_class_install_property (object_class, PROP_SESSION_ID,
- param_spec);
-
param_spec = g_param_spec_string ("authorization-identity",
"AuthorizationIdentity",
"Identity for which we wish to be authorized",
@@ -401,8 +375,7 @@ gabble_server_sasl_channel_class_init (GabbleServerSaslChannelClass *klass)
param_spec = g_param_spec_uint ("sasl-status", "SASLStatus",
"Status of this channel",
- /* FIXME: fix the pluralization in the spec */
- 0, NUM_GABBLE_SASL_STATUSS, 0,
+ 0, NUM_GABBLE_SASL_STATUSES, 0,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
g_object_class_install_property (object_class, PROP_SASL_STATUS,
param_spec);
@@ -971,7 +944,6 @@ gabble_server_sasl_channel_new (GabbleConnection *conn,
"connection", conn,
"available-mechanisms", available_mechanisms,
"secure", secure,
- "session-id", session_id,
NULL));
return obj;