15976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org/*
25976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * libjingle
35976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * Copyright 2004--2005, Google Inc.
45976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *
55976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * Redistribution and use in source and binary forms, with or without
65976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * modification, are permitted provided that the following conditions are met:
75976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *
85976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *  1. Redistributions of source code must retain the above copyright notice,
95976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *     this list of conditions and the following disclaimer.
105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *  2. Redistributions in binary form must reproduce the above copyright notice,
115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *     this list of conditions and the following disclaimer in the documentation
125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *     and/or other materials provided with the distribution.
135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *  3. The name of the author may not be used to endorse or promote products
145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *     derived from this software without specific prior written permission.
155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *
165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org */
275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/xmpp/xmpplogintask.h"
295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <string>
315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <vector>
325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/base64.h"
345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/common.h"
355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/xmllite/xmlelement.h"
365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/xmpp/constants.h"
375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/xmpp/jid.h"
385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/xmpp/saslmechanism.h"
395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/xmpp/xmppengineimpl.h"
405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgusing talk_base::ConstantLabel;
425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgnamespace buzz {
445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#ifdef _DEBUG
465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgconst ConstantLabel XmppLoginTask::LOGINTASK_STATES[] = {
475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  KLABEL(LOGINSTATE_INIT),
485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  KLABEL(LOGINSTATE_STREAMSTART_SENT),
495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  KLABEL(LOGINSTATE_STARTED_XMPP),
505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  KLABEL(LOGINSTATE_TLS_INIT),
515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  KLABEL(LOGINSTATE_AUTH_INIT),
525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  KLABEL(LOGINSTATE_BIND_INIT),
535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  KLABEL(LOGINSTATE_TLS_REQUESTED),
545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  KLABEL(LOGINSTATE_SASL_RUNNING),
555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  KLABEL(LOGINSTATE_BIND_REQUESTED),
565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  KLABEL(LOGINSTATE_SESSION_REQUESTED),
575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  KLABEL(LOGINSTATE_DONE),
585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  LASTLABEL
595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org};
605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif  // _DEBUG
615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgXmppLoginTask::XmppLoginTask(XmppEngineImpl * pctx) :
625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  pctx_(pctx),
635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  authNeeded_(true),
645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  allowNonGoogleLogin_(true),
655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  state_(LOGINSTATE_INIT),
665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  pelStanza_(NULL),
675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  isStart_(false),
685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  iqId_(STR_EMPTY),
69582fe818e571fa2571267f5e369715188472f352wu@webrtc.org  pelFeatures_(),
705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  fullJid_(STR_EMPTY),
715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  streamId_(STR_EMPTY),
725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  pvecQueuedStanzas_(new std::vector<XmlElement *>()),
73582fe818e571fa2571267f5e369715188472f352wu@webrtc.org  sasl_mech_() {
745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgXmppLoginTask::~XmppLoginTask() {
775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  for (size_t i = 0; i < pvecQueuedStanzas_->size(); i += 1)
785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    delete (*pvecQueuedStanzas_)[i];
795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid
825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgXmppLoginTask::IncomingStanza(const XmlElement *element, bool isStart) {
835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  pelStanza_ = element;
845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  isStart_ = isStart;
855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  Advance();
865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  pelStanza_ = NULL;
875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  isStart_ = false;
885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgconst XmlElement *
915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgXmppLoginTask::NextStanza() {
925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  const XmlElement * result = pelStanza_;
935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  pelStanza_ = NULL;
945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return result;
955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool
985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgXmppLoginTask::Advance() {
995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  for (;;) {
1015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    const XmlElement * element = NULL;
1035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#if _DEBUG
1055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG(LS_VERBOSE) << "XmppLoginTask::Advance - "
1065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      << talk_base::ErrorName(state_, LOGINTASK_STATES);
1075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif  // _DEBUG
1085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    switch (state_) {
1105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      case LOGINSTATE_INIT: {
1125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        pctx_->RaiseReset();
1135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        pelFeatures_.reset(NULL);
1145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // The proper domain to verify against is the real underlying
1165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // domain - i.e., the domain that owns the JID.  Our XmppEngineImpl
1175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // also allows matching against a proxy domain instead, if it is told
1185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // to do so - see the implementation of XmppEngineImpl::StartTls and
1195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // XmppEngine::SetTlsServerDomain to see how you can use that feature
1205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        pctx_->InternalSendStart(pctx_->user_jid_.domain());
1215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        state_ = LOGINSTATE_STREAMSTART_SENT;
1225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        break;
1235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
1245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      case LOGINSTATE_STREAMSTART_SENT: {
1265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (NULL == (element = NextStanza()))
1275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          return true;
1285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (!isStart_ || !HandleStartStream(element))
1305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          return Failure(XmppEngine::ERROR_VERSION);
1315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        state_ = LOGINSTATE_STARTED_XMPP;
1335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        return true;
1345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
1355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      case LOGINSTATE_STARTED_XMPP: {
1375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (NULL == (element = NextStanza()))
1385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          return true;
1395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (!HandleFeatures(element))
1415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          return Failure(XmppEngine::ERROR_VERSION);
1425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        bool tls_present = (GetFeature(QN_TLS_STARTTLS) != NULL);
1445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // Error if TLS required but not present.
1455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (pctx_->tls_option_ == buzz::TLS_REQUIRED && !tls_present) {
1465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          return Failure(XmppEngine::ERROR_TLS);
1475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        }
1485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // Use TLS if required or enabled, and also available
1495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if ((pctx_->tls_option_ == buzz::TLS_REQUIRED ||
1505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org            pctx_->tls_option_ == buzz::TLS_ENABLED) && tls_present) {
1515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          state_ = LOGINSTATE_TLS_INIT;
1525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          continue;
1535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        }
1545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (authNeeded_) {
1565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          state_ = LOGINSTATE_AUTH_INIT;
1575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          continue;
1585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        }
1595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        state_ = LOGINSTATE_BIND_INIT;
1615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        continue;
1625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
1635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      case LOGINSTATE_TLS_INIT: {
1655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        const XmlElement * pelTls = GetFeature(QN_TLS_STARTTLS);
1665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (!pelTls)
1675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          return Failure(XmppEngine::ERROR_TLS);
1685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        XmlElement el(QN_TLS_STARTTLS, true);
1705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        pctx_->InternalSendStanza(&el);
1715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        state_ = LOGINSTATE_TLS_REQUESTED;
1725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        continue;
1735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
1745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      case LOGINSTATE_TLS_REQUESTED: {
1765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (NULL == (element = NextStanza()))
1775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          return true;
1785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (element->Name() != QN_TLS_PROCEED)
1795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          return Failure(XmppEngine::ERROR_TLS);
1805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // The proper domain to verify against is the real underlying
1825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // domain - i.e., the domain that owns the JID.  Our XmppEngineImpl
1835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // also allows matching against a proxy domain instead, if it is told
1845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // to do so - see the implementation of XmppEngineImpl::StartTls and
1855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // XmppEngine::SetTlsServerDomain to see how you can use that feature
1865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        pctx_->StartTls(pctx_->user_jid_.domain());
1875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        pctx_->tls_option_ = buzz::TLS_ENABLED;
1885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        state_ = LOGINSTATE_INIT;
1895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        continue;
1905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
1915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      case LOGINSTATE_AUTH_INIT: {
1935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        const XmlElement * pelSaslAuth = GetFeature(QN_SASL_MECHANISMS);
1945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (!pelSaslAuth) {
1955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          return Failure(XmppEngine::ERROR_AUTH);
1965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        }
1975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // Collect together the SASL auth mechanisms presented by the server
1995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        std::vector<std::string> mechanisms;
2005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        for (const XmlElement * pelMech =
2015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org             pelSaslAuth->FirstNamed(QN_SASL_MECHANISM);
2025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org             pelMech;
2035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org             pelMech = pelMech->NextNamed(QN_SASL_MECHANISM)) {
2045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          mechanisms.push_back(pelMech->BodyText());
2065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        }
2075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // Given all the mechanisms, choose the best
2095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        std::string choice(pctx_->ChooseBestSaslMechanism(mechanisms, pctx_->IsEncrypted()));
2105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (choice.empty()) {
2115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          return Failure(XmppEngine::ERROR_AUTH);
2125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        }
2135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // No recognized auth mechanism - that's an error
2155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        sasl_mech_.reset(pctx_->GetSaslMechanism(choice));
2165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (!sasl_mech_) {
2175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          return Failure(XmppEngine::ERROR_AUTH);
2185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        }
2195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // OK, let's start it.
2215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        XmlElement * auth = sasl_mech_->StartSaslAuth();
2225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (auth == NULL) {
2235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          return Failure(XmppEngine::ERROR_AUTH);
2245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        }
2255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (allowNonGoogleLogin_) {
2265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          // Setting the following two attributes is required to support
2275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          // non-google ids.
2285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          // Allow login with non-google id accounts.
2305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          auth->SetAttr(QN_GOOGLE_ALLOW_NON_GOOGLE_ID_XMPP_LOGIN, "true");
2315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          // Allow login with either the non-google id or the friendly email.
2335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          auth->SetAttr(QN_GOOGLE_AUTH_CLIENT_USES_FULL_BIND_RESULT, "true");
2345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        }
2355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        pctx_->InternalSendStanza(auth);
2375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        delete auth;
2385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        state_ = LOGINSTATE_SASL_RUNNING;
2395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        continue;
2405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
2415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      case LOGINSTATE_SASL_RUNNING: {
2435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (NULL == (element = NextStanza()))
2445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          return true;
2455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (element->Name().Namespace() != NS_SASL)
2465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          return Failure(XmppEngine::ERROR_AUTH);
2475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (element->Name() == QN_SASL_CHALLENGE) {
2485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          XmlElement * response = sasl_mech_->HandleSaslChallenge(element);
2495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          if (response == NULL) {
2505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org            return Failure(XmppEngine::ERROR_AUTH);
2515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          }
2525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          pctx_->InternalSendStanza(response);
2535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          delete response;
2545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          state_ = LOGINSTATE_SASL_RUNNING;
2555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          continue;
2565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        }
2575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (element->Name() != QN_SASL_SUCCESS) {
2585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          return Failure(XmppEngine::ERROR_UNAUTHORIZED);
2595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        }
2605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // Authenticated!
2625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        authNeeded_ = false;
2635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        state_ = LOGINSTATE_INIT;
2645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        continue;
2655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
2665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      case LOGINSTATE_BIND_INIT: {
2685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        const XmlElement * pelBindFeature = GetFeature(QN_BIND_BIND);
2695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        const XmlElement * pelSessionFeature = GetFeature(QN_SESSION_SESSION);
2705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (!pelBindFeature || !pelSessionFeature)
2715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          return Failure(XmppEngine::ERROR_BIND);
2725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        XmlElement iq(QN_IQ);
2745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        iq.AddAttr(QN_TYPE, "set");
2755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        iqId_ = pctx_->NextId();
2775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        iq.AddAttr(QN_ID, iqId_);
2785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        iq.AddElement(new XmlElement(QN_BIND_BIND, true));
2795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (pctx_->requested_resource_ != STR_EMPTY) {
2815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          iq.AddElement(new XmlElement(QN_BIND_RESOURCE), 1);
2825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          iq.AddText(pctx_->requested_resource_, 2);
2835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        }
2845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        pctx_->InternalSendStanza(&iq);
2855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        state_ = LOGINSTATE_BIND_REQUESTED;
2865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        continue;
2875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
2885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      case LOGINSTATE_BIND_REQUESTED: {
2905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (NULL == (element = NextStanza()))
2915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          return true;
2925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (element->Name() != QN_IQ || element->Attr(QN_ID) != iqId_ ||
2945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org            element->Attr(QN_TYPE) == "get" || element->Attr(QN_TYPE) == "set")
2955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          return true;
2965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (element->Attr(QN_TYPE) != "result" || element->FirstElement() == NULL ||
2985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org            element->FirstElement()->Name() != QN_BIND_BIND)
2995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          return Failure(XmppEngine::ERROR_BIND);
3005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        fullJid_ = Jid(element->FirstElement()->TextNamed(QN_BIND_JID));
3025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (!fullJid_.IsFull()) {
3035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          return Failure(XmppEngine::ERROR_BIND);
3045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        }
3055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // now request session
3075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        XmlElement iq(QN_IQ);
3085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        iq.AddAttr(QN_TYPE, "set");
3095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        iqId_ = pctx_->NextId();
3115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        iq.AddAttr(QN_ID, iqId_);
3125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        iq.AddElement(new XmlElement(QN_SESSION_SESSION, true));
3135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        pctx_->InternalSendStanza(&iq);
3145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        state_ = LOGINSTATE_SESSION_REQUESTED;
3165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        continue;
3175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
3185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      case LOGINSTATE_SESSION_REQUESTED: {
3205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (NULL == (element = NextStanza()))
3215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          return true;
3225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (element->Name() != QN_IQ || element->Attr(QN_ID) != iqId_ ||
3235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org            element->Attr(QN_TYPE) == "get" || element->Attr(QN_TYPE) == "set")
3245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          return false;
3255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (element->Attr(QN_TYPE) != "result")
3275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          return Failure(XmppEngine::ERROR_BIND);
3285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        pctx_->SignalBound(fullJid_);
3305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        FlushQueuedStanzas();
3315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        state_ = LOGINSTATE_DONE;
3325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        return true;
3335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
3345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      case LOGINSTATE_DONE:
3365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        return false;
3375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
3385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
3395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
3405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool
3425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgXmppLoginTask::HandleStartStream(const XmlElement *element) {
3435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (element->Name() != QN_STREAM_STREAM)
3455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
3465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (element->Attr(QN_XMLNS) != "jabber:client")
3485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
3495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (element->Attr(QN_VERSION) != "1.0")
3515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
3525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (!element->HasAttr(QN_ID))
3545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
3555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  streamId_ = element->Attr(QN_ID);
3575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
3595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
3605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool
3625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgXmppLoginTask::HandleFeatures(const XmlElement *element) {
3635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (element->Name() != QN_STREAM_FEATURES)
3645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
3655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  pelFeatures_.reset(new XmlElement(*element));
3675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
3685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
3695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgconst XmlElement *
3715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgXmppLoginTask::GetFeature(const QName & name) {
3725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return pelFeatures_->FirstNamed(name);
3735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
3745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool
3765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgXmppLoginTask::Failure(XmppEngine::Error reason) {
3775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  state_ = LOGINSTATE_DONE;
3785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  pctx_->SignalError(reason, 0);
3795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return false;
3805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
3815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid
3835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgXmppLoginTask::OutgoingStanza(const XmlElement * element) {
3845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  XmlElement * pelCopy = new XmlElement(*element);
3855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  pvecQueuedStanzas_->push_back(pelCopy);
3865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
3875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid
3895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgXmppLoginTask::FlushQueuedStanzas() {
3905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  for (size_t i = 0; i < pvecQueuedStanzas_->size(); i += 1) {
3915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    pctx_->InternalSendStanza((*pvecQueuedStanzas_)[i]);
3925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    delete (*pvecQueuedStanzas_)[i];
3935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
3945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  pvecQueuedStanzas_->clear();
3955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
3965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
398