1 /* 2 * protocol.h - XMPP-Core protocol state machine 3 * Copyright (C) 2004 Justin Karneges 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * either version 2 9 of the License, or (at your option) any later version.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 20 */ 21 22 #ifndef PROTOCOL_H 23 #define PROTOCOL_H 24 25 #include <QPair> 26 //Added by qt3to4: 27 #include <QList> 28 #include "xmlprotocol.h" 29 #include "xmpp.h" 30 31 #define NS_ETHERX "http://etherx.jabber.org/streams" 32 #define NS_CLIENT "jabber:client" 33 #define NS_SERVER "jabber:server" 34 #define NS_DIALBACK "jabber:server:dialback" 35 #define NS_STREAMS "urn:ietf:params:xml:ns:xmpp-streams" 36 #define NS_TLS "urn:ietf:params:xml:ns:xmpp-tls" 37 #define NS_SASL "urn:ietf:params:xml:ns:xmpp-sasl" 38 #define NS_SESSION "urn:ietf:params:xml:ns:xmpp-session" 39 #define NS_STANZAS "urn:ietf:params:xml:ns:xmpp-stanzas" 40 #define NS_BIND "urn:ietf:params:xml:ns:xmpp-bind" 41 #define NS_COMPRESS_FEATURE "http://jabber.org/features/compress" 42 #define NS_COMPRESS_PROTOCOL "http://jabber.org/protocol/compress" 43 #define NS_HOSTS "http://barracuda.com/xmppextensions/hosts" 44 45 namespace XMPP 46 { 47 class Version 48 { 49 public: 50 Version(int maj=0, int min=0); 51 52 int major, minor; 53 }; 54 55 class StreamFeatures 56 { 57 public: 58 StreamFeatures(); 59 60 bool tls_supported, sasl_supported, bind_supported, compress_supported; 61 bool tls_required; 62 QStringList sasl_mechs; 63 QStringList compression_mechs; 64 QStringList hosts; 65 }; 66 67 class BasicProtocol : public XmlProtocol 68 { 69 public: 70 // xmpp 1.0 error conditions 71 enum SASLCond { 72 Aborted, 73 IncorrectEncoding, 74 InvalidAuthzid, 75 InvalidMech, 76 MechTooWeak, 77 NotAuthorized, 78 TemporaryAuthFailure 79 }; 80 enum StreamCond { 81 BadFormat, 82 BadNamespacePrefix, 83 Conflict, 84 ConnectionTimeout, 85 HostGone, 86 HostUnknown, 87 ImproperAddressing, 88 InternalServerError, 89 InvalidFrom, 90 InvalidId, 91 InvalidNamespace, 92 InvalidXml, 93 StreamNotAuthorized, 94 PolicyViolation, 95 RemoteConnectionFailed, 96 ResourceConstraint, 97 RestrictedXml, 98 SeeOtherHost, 99 SystemShutdown, 100 UndefinedCondition, 101 UnsupportedEncoding, 102 UnsupportedStanzaType, 103 UnsupportedVersion, 104 XmlNotWellFormed 105 }; 106 enum BindCond { 107 BindBadRequest, 108 BindNotAllowed, 109 BindConflict 110 }; 111 112 // extend the XmlProtocol enums 113 enum Need { 114 NSASLMechs = XmlProtocol::NCustom, // need SASL mechlist 115 NStartTLS, // need to switch on TLS layer 116 NCompress, // need to switch on compression layer 117 NSASLFirst, // need SASL first step 118 NSASLNext, // need SASL next step 119 NSASLLayer, // need to switch on SASL layer 120 NCustom = XmlProtocol::NCustom+10 121 }; 122 enum Event { 123 EFeatures = XmlProtocol::ECustom, // breakpoint after features packet is received 124 ESASLSuccess, // breakpoint after successful sasl auth 125 EStanzaReady, // a stanza was received 126 EStanzaSent, // a stanza was sent 127 EReady, // stream is ready for stanza use 128 ECustom = XmlProtocol::ECustom+10 129 }; 130 enum Error { 131 ErrProtocol = XmlProtocol::ErrCustom, // there was an error in the xmpp-core protocol exchange 132 ErrStream, // <stream:error>, see errCond, errText, and errAppSpec for details 133 ErrStartTLS, // server refused starttls 134 ErrCompress, // server refused compression 135 ErrAuth, // authorization error. errCond holds sasl condition (or numeric code for old-protocol) 136 ErrBind, // server refused resource bind 137 ErrCustom = XmlProtocol::ErrCustom+10 138 }; 139 140 BasicProtocol(); 141 ~BasicProtocol() override; 142 143 void reset() override; 144 145 // for outgoing xml 146 QDomDocument doc; 147 148 // sasl-related 149 QString saslMech() const; 150 QByteArray saslStep() const; 151 void setSASLMechList(const QStringList &list); 152 void setSASLFirst(const QString &mech, const QByteArray &step); 153 void setSASLNext(const QByteArray &step); 154 void setSASLAuthed(); 155 156 // send / recv 157 void sendStanza(const QDomElement &e); 158 void sendDirect(const QString &s); 159 void sendWhitespace(); 160 QDomElement recvStanza(); 161 162 // shutdown 163 void shutdown(); 164 void shutdownWithError(int cond, const QString &otherHost=""); 165 166 // <stream> information 167 QString to, from, id, lang; 168 Version version; 169 170 // error output 171 int errCond; 172 QString errText; 173 QDomElement errAppSpec; 174 QString otherHost; 175 176 QByteArray spare; // filled with unprocessed data on NStartTLS and NSASLLayer 177 178 bool isReady() const; 179 180 enum { TypeElement, TypeStanza, TypeDirect, TypePing }; 181 182 protected: 183 static int stringToSASLCond(const QString &s); 184 static int stringToStreamCond(const QString &s); 185 static QString saslCondToString(int); 186 static QString streamCondToString(int); 187 188 void send(const QDomElement &e, bool clip=false); 189 void sendStreamError(int cond, const QString &text="", const QDomElement &appSpec=QDomElement()); 190 void sendStreamError(const QString &text); // old-style 191 192 bool errorAndClose(int cond, const QString &text="", const QDomElement &appSpec=QDomElement()); 193 bool error(int code); 194 void delayErrorAndClose(int cond, const QString &text="", const QDomElement &appSpec=QDomElement()); 195 void delayError(int code); 196 197 // reimplemented 198 QDomElement docElement() override; 199 void handleDocOpen(const Parser::Event &pe) override; 200 bool handleError() override; 201 bool handleCloseFinished() override; 202 bool doStep(const QDomElement &e) override; 203 void itemWritten(int id, int size) override; 204 205 virtual QString defaultNamespace(); 206 virtual QStringList extraNamespaces(); // stringlist: prefix,uri,prefix,uri, [...] 207 virtual void handleStreamOpen(const Parser::Event &pe); 208 virtual bool doStep2(const QDomElement &e)=0; 209 210 void setReady(bool b); 211 212 QString sasl_mech; 213 QStringList sasl_mechlist; 214 QByteArray sasl_step; 215 bool sasl_authed; 216 217 QDomElement stanzaToRecv; 218 219 private: 220 struct SASLCondEntry 221 { 222 const char *str; 223 int cond; 224 }; 225 static SASLCondEntry saslCondTable[]; 226 227 struct StreamCondEntry 228 { 229 const char *str; 230 int cond; 231 }; 232 static StreamCondEntry streamCondTable[]; 233 234 struct SendItem 235 { 236 QDomElement stanzaToSend; 237 QString stringToSend; 238 bool doWhitespace; 239 }; 240 QList<SendItem> sendList; 241 242 bool doShutdown, delayedError, closeError, ready; 243 int stanzasPending, stanzasWritten; 244 245 void init(); 246 void extractStreamError(const QDomElement &e); 247 }; 248 249 class CoreProtocol : public BasicProtocol 250 { 251 public: 252 enum { 253 NPassword = NCustom, // need password for old-mode 254 EDBVerify = ECustom, // breakpoint after db:verify request 255 ErrPlain = ErrCustom // server only supports plain, but allowPlain is false locally 256 }; 257 258 CoreProtocol(); 259 ~CoreProtocol() override; 260 261 void reset() override; 262 263 void startClientOut(const Jid &jid, bool oldOnly, bool tlsActive, bool doAuth, bool doCompression); 264 void startServerOut(const QString &to); 265 void startDialbackOut(const QString &to, const QString &from); 266 void startDialbackVerifyOut(const QString &to, const QString &from, const QString &id, const QString &key); 267 void startClientIn(const QString &id); 268 void startServerIn(const QString &id); 269 270 void setLang(const QString &s); 271 void setAllowTLS(bool b); 272 void setAllowBind(bool b); 273 void setAllowPlain(bool b); // old-mode 274 const Jid& jid() const; 275 276 void setPassword(const QString &s); 277 void setFrom(const QString &s); 278 void setDialbackKey(const QString &s); 279 280 // input 281 QString user, host; 282 283 // status 284 bool old; 285 286 StreamFeatures features; 287 QStringList hosts; 288 289 //static QString xmlToString(const QDomElement &e, bool clip=false); 290 291 class DBItem 292 { 293 public: 294 enum { ResultRequest, ResultGrant, VerifyRequest, VerifyGrant, Validated }; 295 int type; 296 Jid to, from; 297 QString key, id; 298 bool ok; 299 }; 300 301 private: 302 enum Step { 303 Start, 304 Done, 305 SendFeatures, 306 GetRequest, 307 HandleTLS, 308 GetSASLResponse, 309 IncHandleSASLSuccess, 310 GetFeatures, // read features packet 311 HandleFeatures, // act on features, by initiating tls, sasl, or bind 312 GetTLSProceed, // read <proceed/> tls response 313 GetCompressProceed, // read <compressed/> compression response 314 GetSASLFirst, // perform sasl first step using provided data 315 GetSASLChallenge, // read server sasl challenge 316 GetSASLNext, // perform sasl next step using provided data 317 HandleSASLSuccess, // handle what must be done after reporting sasl success 318 GetBindResponse, // read bind response 319 HandleAuthGet, // send old-protocol auth-get 320 GetAuthGetResponse, // read auth-get response 321 HandleAuthSet, // send old-protocol auth-set 322 GetAuthSetResponse // read auth-set response 323 }; 324 325 QList<DBItem> dbrequests, dbpending, dbvalidated; 326 327 bool server, dialback, dialback_verify; 328 int step; 329 330 bool digest; 331 bool tls_started, sasl_started, compress_started; 332 333 Jid jid_; 334 bool oldOnly; 335 bool allowPlain; 336 bool doTLS, doAuth, doBinding, doCompress; 337 QString password; 338 339 QString dialback_id, dialback_key; 340 QString self_from; 341 342 void init(); 343 static int getOldErrorCode(const QDomElement &e); 344 bool loginComplete(); 345 346 bool isValidStanza(const QDomElement &e) const; 347 bool grabPendingItem(const Jid &to, const Jid &from, int type, DBItem *item); 348 bool normalStep(const QDomElement &e); 349 bool dialbackStep(const QDomElement &e); 350 351 // reimplemented 352 bool stepAdvancesParser() const override; 353 bool stepRequiresElement() const override; 354 void stringSend(const QString &s) override; 355 void stringRecv(const QString &s) override; 356 QString defaultNamespace() override; 357 QStringList extraNamespaces() override; 358 void handleStreamOpen(const Parser::Event &pe) override; 359 bool doStep2(const QDomElement &e) override; 360 void elementSend(const QDomElement &e) override; 361 void elementRecv(const QDomElement &e) override; 362 }; 363 } 364 365 #endif 366