1f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch/*
2f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * libjingle
3f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * Copyright 2004--2005, Google Inc.
4f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *
5f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * Redistribution and use in source and binary forms, with or without
6f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * modification, are permitted provided that the following conditions are met:
7f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *
8f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *  1. Redistributions of source code must retain the above copyright notice,
9f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *     this list of conditions and the following disclaimer.
10f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *  2. Redistributions in binary form must reproduce the above copyright notice,
11f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *     this list of conditions and the following disclaimer in the documentation
12f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *     and/or other materials provided with the distribution.
13f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *  3. The name of the author may not be used to endorse or promote products
14f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *     derived from this software without specific prior written permission.
15f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *
16f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch */
27f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
28f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include <iostream>
29f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include <string>
30f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include <vector>
31f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/base64.h"
32f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/common.h"
33f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/xmllite/xmlelement.h"
34f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/xmpp/constants.h"
35f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/xmpp/jid.h"
36f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/xmpp/saslmechanism.h"
37f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/xmpp/xmppengineimpl.h"
38f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/xmpp/xmpplogintask.h"
39f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
40f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochusing talk_base::ConstantLabel;
41f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
42f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochnamespace buzz {
43f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
44f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#ifdef _DEBUG
45f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochconst ConstantLabel XmppLoginTask::LOGINTASK_STATES[] = {
46f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  KLABEL(LOGINSTATE_INIT),
47f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  KLABEL(LOGINSTATE_STREAMSTART_SENT),
48f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  KLABEL(LOGINSTATE_STARTED_XMPP),
49f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  KLABEL(LOGINSTATE_TLS_INIT),
50f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  KLABEL(LOGINSTATE_AUTH_INIT),
51f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  KLABEL(LOGINSTATE_BIND_INIT),
52f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  KLABEL(LOGINSTATE_TLS_REQUESTED),
53f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  KLABEL(LOGINSTATE_SASL_RUNNING),
54f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  KLABEL(LOGINSTATE_BIND_REQUESTED),
55f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  KLABEL(LOGINSTATE_SESSION_REQUESTED),
56f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  KLABEL(LOGINSTATE_DONE),
57f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  LASTLABEL
58f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch};
59f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#endif  // _DEBUG
60f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
61f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochXmppLoginTask::XmppLoginTask(XmppEngineImpl * pctx) :
62f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  pctx_(pctx),
63f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  authNeeded_(true),
64f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  state_(LOGINSTATE_INIT),
65f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  pelStanza_(NULL),
66f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  isStart_(false),
67f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  iqId_(STR_EMPTY),
68f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  pelFeatures_(NULL),
69f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  fullJid_(STR_EMPTY),
70f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  streamId_(STR_EMPTY),
71f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  pvecQueuedStanzas_(new std::vector<XmlElement *>()),
72f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  sasl_mech_(NULL) {
73f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
74f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
75f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochXmppLoginTask::~XmppLoginTask() {
76f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  for (size_t i = 0; i < pvecQueuedStanzas_->size(); i += 1)
77f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    delete (*pvecQueuedStanzas_)[i];
78f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
79f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
80f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid
81f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochXmppLoginTask::IncomingStanza(const XmlElement *element, bool isStart) {
82f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  pelStanza_ = element;
83f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  isStart_ = isStart;
84f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  Advance();
85f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  pelStanza_ = NULL;
86f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  isStart_ = false;
87f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
88f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
89f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochconst XmlElement *
90f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochXmppLoginTask::NextStanza() {
91f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  const XmlElement * result = pelStanza_;
92f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  pelStanza_ = NULL;
93f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return result;
94f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
95f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
96f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool
97f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochXmppLoginTask::Advance() {
98f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
99f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  for (;;) {
100f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
101f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    const XmlElement * element = NULL;
102f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
103f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#if _DEBUG
104f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    LOG(LS_VERBOSE) << "XmppLoginTask::Advance - "
105f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      << talk_base::ErrorName(state_, LOGINTASK_STATES);
106f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#endif  // _DEBUG
107f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
108f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    switch (state_) {
109f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
110f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      case LOGINSTATE_INIT: {
111f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        pctx_->RaiseReset();
112f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        pelFeatures_.reset(NULL);
113f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
114f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        // The proper domain to verify against is the real underlying
115f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        // domain - i.e., the domain that owns the JID.  Our XmppEngineImpl
116f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        // also allows matching against a proxy domain instead, if it is told
117f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        // to do so - see the implementation of XmppEngineImpl::StartTls and
118f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        // XmppEngine::SetTlsServerDomain to see how you can use that feature
119f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        pctx_->InternalSendStart(pctx_->user_jid_.domain());
120f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        state_ = LOGINSTATE_STREAMSTART_SENT;
121f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        break;
122f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      }
123f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
124f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      case LOGINSTATE_STREAMSTART_SENT: {
125f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        if (NULL == (element = NextStanza()))
126f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          return true;
127f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
128f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        if (!isStart_ || !HandleStartStream(element))
129f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          return Failure(XmppEngine::ERROR_VERSION);
130f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
131f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        state_ = LOGINSTATE_STARTED_XMPP;
132f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        return true;
133f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      }
134f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
135f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      case LOGINSTATE_STARTED_XMPP: {
136f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        if (NULL == (element = NextStanza()))
137f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          return true;
138f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
139f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        if (!HandleFeatures(element))
140f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          return Failure(XmppEngine::ERROR_VERSION);
141f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
142f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        // Use TLS if forced, or if available
143f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        if (pctx_->tls_needed_ || GetFeature(QN_TLS_STARTTLS) != NULL) {
144f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          state_ = LOGINSTATE_TLS_INIT;
145f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          continue;
146f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        }
147f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
148f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        if (authNeeded_) {
149f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          state_ = LOGINSTATE_AUTH_INIT;
150f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          continue;
151f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        }
152f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
153f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        state_ = LOGINSTATE_BIND_INIT;
154f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        continue;
155f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      }
156f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
157f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      case LOGINSTATE_TLS_INIT: {
158f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        const XmlElement * pelTls = GetFeature(QN_TLS_STARTTLS);
159f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        if (!pelTls)
160f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          return Failure(XmppEngine::ERROR_TLS);
161f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
162f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        XmlElement el(QN_TLS_STARTTLS, true);
163f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        pctx_->InternalSendStanza(&el);
164f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        state_ = LOGINSTATE_TLS_REQUESTED;
165f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        continue;
166f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      }
167f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
168f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      case LOGINSTATE_TLS_REQUESTED: {
169f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        if (NULL == (element = NextStanza()))
170f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          return true;
171f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        if (element->Name() != QN_TLS_PROCEED)
172f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          return Failure(XmppEngine::ERROR_TLS);
173f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
174f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        // The proper domain to verify against is the real underlying
175f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        // domain - i.e., the domain that owns the JID.  Our XmppEngineImpl
176f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        // also allows matching against a proxy domain instead, if it is told
177f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        // to do so - see the implementation of XmppEngineImpl::StartTls and
178f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        // XmppEngine::SetTlsServerDomain to see how you can use that feature
179f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        pctx_->StartTls(pctx_->user_jid_.domain());
180f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        pctx_->tls_needed_ = false;
181f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        state_ = LOGINSTATE_INIT;
182f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        continue;
183f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      }
184f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
185f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      case LOGINSTATE_AUTH_INIT: {
186f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        const XmlElement * pelSaslAuth = GetFeature(QN_SASL_MECHANISMS);
187f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        if (!pelSaslAuth) {
188f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          return Failure(XmppEngine::ERROR_AUTH);
189f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        }
190f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
191f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        // Collect together the SASL auth mechanisms presented by the server
192f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        std::vector<std::string> mechanisms;
193f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        for (const XmlElement * pelMech =
194f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch             pelSaslAuth->FirstNamed(QN_SASL_MECHANISM);
195f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch             pelMech;
196f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch             pelMech = pelMech->NextNamed(QN_SASL_MECHANISM)) {
197f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
198f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          mechanisms.push_back(pelMech->BodyText());
199f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        }
200f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
201f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        // Given all the mechanisms, choose the best
202f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        std::string choice(pctx_->ChooseBestSaslMechanism(mechanisms, pctx_->IsEncrypted()));
203f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        if (choice.empty()) {
204f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          return Failure(XmppEngine::ERROR_AUTH);
205f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        }
206f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
207f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        // No recognized auth mechanism - that's an error
208f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        sasl_mech_.reset(pctx_->GetSaslMechanism(choice));
209f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        if (sasl_mech_.get() == NULL) {
210f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          return Failure(XmppEngine::ERROR_AUTH);
211f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        }
212f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
213f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        // OK, let's start it.
214f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        XmlElement * auth = sasl_mech_->StartSaslAuth();
215f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        if (auth == NULL) {
216f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          return Failure(XmppEngine::ERROR_AUTH);
217f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        }
218f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
219f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        pctx_->InternalSendStanza(auth);
220f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        delete auth;
221f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        state_ = LOGINSTATE_SASL_RUNNING;
222f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        continue;
223f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      }
224f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
225f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      case LOGINSTATE_SASL_RUNNING: {
226f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        if (NULL == (element = NextStanza()))
227f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          return true;
228f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        if (element->Name().Namespace() != NS_SASL)
229f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          return Failure(XmppEngine::ERROR_AUTH);
230f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        if (element->Name() == QN_SASL_CHALLENGE) {
231f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          XmlElement * response = sasl_mech_->HandleSaslChallenge(element);
232f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          if (response == NULL) {
233f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch            return Failure(XmppEngine::ERROR_AUTH);
234f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          }
235f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          pctx_->InternalSendStanza(response);
236f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          delete response;
237f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          state_ = LOGINSTATE_SASL_RUNNING;
238f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          continue;
239f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        }
240f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        if (element->Name() != QN_SASL_SUCCESS) {
241f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          return Failure(XmppEngine::ERROR_UNAUTHORIZED);
242f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        }
243f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
244f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        // Authenticated!
245f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        authNeeded_ = false;
246f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        state_ = LOGINSTATE_INIT;
247f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        continue;
248f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      }
249f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
250f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      case LOGINSTATE_BIND_INIT: {
251f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        const XmlElement * pelBindFeature = GetFeature(QN_BIND_BIND);
252f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        const XmlElement * pelSessionFeature = GetFeature(QN_SESSION_SESSION);
253f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        if (!pelBindFeature || !pelSessionFeature)
254f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          return Failure(XmppEngine::ERROR_BIND);
255f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
256f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        XmlElement iq(QN_IQ);
257f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        iq.AddAttr(QN_TYPE, "set");
258f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
259f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        iqId_ = pctx_->NextId();
260f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        iq.AddAttr(QN_ID, iqId_);
261f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        iq.AddElement(new XmlElement(QN_BIND_BIND, true));
262f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
263f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        if (pctx_->requested_resource_ != STR_EMPTY) {
264f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          iq.AddElement(new XmlElement(QN_BIND_RESOURCE), 1);
265f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          iq.AddText(pctx_->requested_resource_, 2);
266f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        }
267f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        pctx_->InternalSendStanza(&iq);
268f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        state_ = LOGINSTATE_BIND_REQUESTED;
269f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        continue;
270f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      }
271f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
272f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      case LOGINSTATE_BIND_REQUESTED: {
273f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        if (NULL == (element = NextStanza()))
274f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          return true;
275f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
276f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        if (element->Name() != QN_IQ || element->Attr(QN_ID) != iqId_ ||
277f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch            element->Attr(QN_TYPE) == "get" || element->Attr(QN_TYPE) == "set")
278f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          return true;
279f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
280f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        if (element->Attr(QN_TYPE) != "result" || element->FirstElement() == NULL ||
281f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch            element->FirstElement()->Name() != QN_BIND_BIND)
282f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          return Failure(XmppEngine::ERROR_BIND);
283f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
284f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        fullJid_ = Jid(element->FirstElement()->TextNamed(QN_BIND_JID));
285f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        if (!fullJid_.IsFull()) {
286f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          return Failure(XmppEngine::ERROR_BIND);
287f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        }
288f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
289f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        // now request session
290f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        XmlElement iq(QN_IQ);
291f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        iq.AddAttr(QN_TYPE, "set");
292f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
293f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        iqId_ = pctx_->NextId();
294f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        iq.AddAttr(QN_ID, iqId_);
295f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        iq.AddElement(new XmlElement(QN_SESSION_SESSION, true));
296f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        pctx_->InternalSendStanza(&iq);
297f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
298f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        state_ = LOGINSTATE_SESSION_REQUESTED;
299f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        continue;
300f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      }
301f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
302f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      case LOGINSTATE_SESSION_REQUESTED: {
303f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        if (NULL == (element = NextStanza()))
304f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          return true;
305f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        if (element->Name() != QN_IQ || element->Attr(QN_ID) != iqId_ ||
306f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch            element->Attr(QN_TYPE) == "get" || element->Attr(QN_TYPE) == "set")
307f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          return false;
308f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
309f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        if (element->Attr(QN_TYPE) != "result")
310f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          return Failure(XmppEngine::ERROR_BIND);
311f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
312f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        pctx_->SignalBound(fullJid_);
313f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        FlushQueuedStanzas();
314f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        state_ = LOGINSTATE_DONE;
315f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        return true;
316f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      }
317f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
318f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      case LOGINSTATE_DONE:
319f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        return false;
320f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
321f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
322f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
323f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
324f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool
325f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochXmppLoginTask::HandleStartStream(const XmlElement *element) {
326f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
327f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (element->Name() != QN_STREAM_STREAM)
328f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
329f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
330f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (element->Attr(QN_XMLNS) != "jabber:client")
331f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
332f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
333f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (element->Attr(QN_VERSION) != "1.0")
334f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
335f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
336f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (!element->HasAttr(QN_ID))
337f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
338f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
339f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  streamId_ = element->Attr(QN_ID);
340f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
341f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return true;
342f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
343f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
344f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool
345f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochXmppLoginTask::HandleFeatures(const XmlElement *element) {
346f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (element->Name() != QN_STREAM_FEATURES)
347f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
348f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
349f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  pelFeatures_.reset(new XmlElement(*element));
350f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return true;
351f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
352f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
353f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochconst XmlElement *
354f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochXmppLoginTask::GetFeature(const QName & name) {
355f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return pelFeatures_->FirstNamed(name);
356f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
357f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
358f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool
359f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochXmppLoginTask::Failure(XmppEngine::Error reason) {
360f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  state_ = LOGINSTATE_DONE;
361f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  pctx_->SignalError(reason, 0);
362f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return false;
363f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
364f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
365f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid
366f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochXmppLoginTask::OutgoingStanza(const XmlElement * element) {
367f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  XmlElement * pelCopy = new XmlElement(*element);
368f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  pvecQueuedStanzas_->push_back(pelCopy);
369f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
370f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
371f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid
372f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochXmppLoginTask::FlushQueuedStanzas() {
373f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  for (size_t i = 0; i < pvecQueuedStanzas_->size(); i += 1) {
374f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    pctx_->InternalSendStanza((*pvecQueuedStanzas_)[i]);
375f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    delete (*pvecQueuedStanzas_)[i];
376f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
377f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  pvecQueuedStanzas_->clear();
378f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
379f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
380f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
381