Line data Source code
1 : /* SPDX-License-Identifier: MIT OR GPL-3.0-only */
2 : /* auth.c
3 : ** strophe XMPP client library -- auth functions and handlers
4 : **
5 : ** Copyright (C) 2005-2009 Collecta, Inc.
6 : **
7 : ** This software is provided AS-IS with no warranty, either express or
8 : ** implied.
9 : **
10 : ** This program is dual licensed under the MIT or GPLv3 licenses.
11 : */
12 :
13 : /** @file
14 : * Authentication function and handlers.
15 : */
16 :
17 : #include <stdio.h>
18 : #include <stdlib.h>
19 : #include <string.h>
20 :
21 : #include "strophe.h"
22 : #include "common.h"
23 : #include "sasl.h"
24 : #include "sha1.h"
25 :
26 : #ifdef _MSC_VER
27 : #define strcasecmp _stricmp
28 : #endif
29 :
30 : /* TODO: these should configurable at runtime on a per connection basis */
31 :
32 : #ifndef FEATURES_TIMEOUT
33 : /** @def FEATURES_TIMEOUT
34 : * Time to wait for <stream:features/> stanza.
35 : */
36 : #define FEATURES_TIMEOUT 15000 /* 15 seconds */
37 : #endif
38 : #ifndef BIND_TIMEOUT
39 : /** @def BIND_TIMEOUT
40 : * Time to wait for <bind/> stanza reply.
41 : */
42 : #define BIND_TIMEOUT 15000 /* 15 seconds */
43 : #endif
44 : #ifndef SESSION_TIMEOUT
45 : /** @def SESSION_TIMEOUT
46 : * Time to wait for <session/> stanza reply.
47 : */
48 : #define SESSION_TIMEOUT 15000 /* 15 seconds */
49 : #endif
50 : #ifndef LEGACY_TIMEOUT
51 : /** @def LEGACY_TIMEOUT
52 : * Time to wait for legacy authentication to complete.
53 : */
54 : #define LEGACY_TIMEOUT 15000 /* 15 seconds */
55 : #endif
56 : #ifndef HANDSHAKE_TIMEOUT
57 : /** @def HANDSHAKE_TIMEOUT
58 : * Time to wait for component authentication to complete
59 : */
60 : #define HANDSHAKE_TIMEOUT 15000 /* 15 seconds */
61 : #endif
62 :
63 : static void _auth(xmpp_conn_t *conn);
64 : static void _auth_legacy(xmpp_conn_t *conn);
65 : static void _handle_open_compress(xmpp_conn_t *conn);
66 : static void _handle_open_sasl(xmpp_conn_t *conn);
67 : static void _handle_open_tls(xmpp_conn_t *conn);
68 :
69 : static int _handle_component_auth(xmpp_conn_t *conn);
70 : static int _handle_component_hs_response(xmpp_conn_t *conn,
71 : xmpp_stanza_t *stanza,
72 : void *userdata);
73 :
74 : static int
75 : _handle_features_sasl(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata);
76 : static int _handle_features_compress(xmpp_conn_t *conn,
77 : xmpp_stanza_t *stanza,
78 : void *userdata);
79 : static int
80 : _handle_sasl_result(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata);
81 : static int _handle_digestmd5_challenge(xmpp_conn_t *conn,
82 : xmpp_stanza_t *stanza,
83 : void *userdata);
84 : static int _handle_digestmd5_rspauth(xmpp_conn_t *conn,
85 : xmpp_stanza_t *stanza,
86 : void *userdata);
87 : static int _handle_scram_challenge(xmpp_conn_t *conn,
88 : xmpp_stanza_t *stanza,
89 : void *userdata);
90 : struct scram_user_data;
91 : static int _make_scram_init_msg(struct scram_user_data *scram);
92 :
93 : static int _handle_missing_features_sasl(xmpp_conn_t *conn, void *userdata);
94 : static int _handle_missing_bind(xmpp_conn_t *conn, void *userdata);
95 : static int
96 : _handle_bind(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata);
97 : static int
98 : _handle_session(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata);
99 : static int _handle_missing_session(xmpp_conn_t *conn, void *userdata);
100 : static int _handle_missing_handshake(xmpp_conn_t *conn, void *userdata);
101 : static int _handle_sm(xmpp_conn_t *const conn,
102 : xmpp_stanza_t *const stanza,
103 : void *const userdata);
104 :
105 : /* stream:error handler */
106 : static int
107 0 : _handle_error(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
108 : {
109 0 : xmpp_stanza_t *child;
110 0 : const char *name;
111 :
112 0 : UNUSED(userdata);
113 :
114 : /* free old stream error if it's still there */
115 0 : if (conn->stream_error) {
116 0 : xmpp_stanza_release(conn->stream_error->stanza);
117 0 : if (conn->stream_error->text)
118 0 : strophe_free(conn->ctx, conn->stream_error->text);
119 0 : strophe_free(conn->ctx, conn->stream_error);
120 : }
121 :
122 : /* create stream error structure */
123 0 : conn->stream_error = (xmpp_stream_error_t *)strophe_alloc(
124 0 : conn->ctx, sizeof(xmpp_stream_error_t));
125 :
126 0 : conn->stream_error->text = NULL;
127 0 : conn->stream_error->type = XMPP_SE_UNDEFINED_CONDITION;
128 :
129 0 : if (conn->stream_error) {
130 0 : child = xmpp_stanza_get_children(stanza);
131 0 : do {
132 0 : const char *ns = NULL;
133 :
134 0 : if (child) {
135 0 : ns = xmpp_stanza_get_ns(child);
136 : }
137 :
138 0 : if (ns && strcmp(ns, XMPP_NS_STREAMS_IETF) == 0) {
139 0 : name = xmpp_stanza_get_name(child);
140 0 : if (strcmp(name, "text") == 0) {
141 0 : if (conn->stream_error->text)
142 0 : strophe_free(conn->ctx, conn->stream_error->text);
143 0 : conn->stream_error->text = xmpp_stanza_get_text(child);
144 0 : } else if (strcmp(name, "bad-format") == 0)
145 0 : conn->stream_error->type = XMPP_SE_BAD_FORMAT;
146 0 : else if (strcmp(name, "bad-namespace-prefix") == 0)
147 0 : conn->stream_error->type = XMPP_SE_BAD_NS_PREFIX;
148 0 : else if (strcmp(name, "conflict") == 0)
149 0 : conn->stream_error->type = XMPP_SE_CONFLICT;
150 0 : else if (strcmp(name, "connection-timeout") == 0)
151 0 : conn->stream_error->type = XMPP_SE_CONN_TIMEOUT;
152 0 : else if (strcmp(name, "host-gone") == 0)
153 0 : conn->stream_error->type = XMPP_SE_HOST_GONE;
154 0 : else if (strcmp(name, "host-unknown") == 0)
155 0 : conn->stream_error->type = XMPP_SE_HOST_UNKNOWN;
156 0 : else if (strcmp(name, "improper-addressing") == 0)
157 0 : conn->stream_error->type = XMPP_SE_IMPROPER_ADDR;
158 0 : else if (strcmp(name, "internal-server-error") == 0)
159 0 : conn->stream_error->type = XMPP_SE_INTERNAL_SERVER_ERROR;
160 0 : else if (strcmp(name, "invalid-from") == 0)
161 0 : conn->stream_error->type = XMPP_SE_INVALID_FROM;
162 0 : else if (strcmp(name, "invalid-id") == 0)
163 0 : conn->stream_error->type = XMPP_SE_INVALID_ID;
164 0 : else if (strcmp(name, "invalid-namespace") == 0)
165 0 : conn->stream_error->type = XMPP_SE_INVALID_NS;
166 0 : else if (strcmp(name, "invalid-xml") == 0)
167 0 : conn->stream_error->type = XMPP_SE_INVALID_XML;
168 0 : else if (strcmp(name, "not-authorized") == 0)
169 0 : conn->stream_error->type = XMPP_SE_NOT_AUTHORIZED;
170 0 : else if (strcmp(name, "policy-violation") == 0)
171 0 : conn->stream_error->type = XMPP_SE_POLICY_VIOLATION;
172 0 : else if (strcmp(name, "remote-connection-failed") == 0)
173 0 : conn->stream_error->type = XMPP_SE_REMOTE_CONN_FAILED;
174 0 : else if (strcmp(name, "resource-constraint") == 0)
175 0 : conn->stream_error->type = XMPP_SE_RESOURCE_CONSTRAINT;
176 0 : else if (strcmp(name, "restricted-xml") == 0)
177 0 : conn->stream_error->type = XMPP_SE_RESTRICTED_XML;
178 0 : else if (strcmp(name, "see-other-host") == 0)
179 0 : conn->stream_error->type = XMPP_SE_SEE_OTHER_HOST;
180 0 : else if (strcmp(name, "system-shutdown") == 0)
181 0 : conn->stream_error->type = XMPP_SE_SYSTEM_SHUTDOWN;
182 0 : else if (strcmp(name, "undefined-condition") == 0)
183 0 : conn->stream_error->type = XMPP_SE_UNDEFINED_CONDITION;
184 0 : else if (strcmp(name, "unsupported-encoding") == 0)
185 0 : conn->stream_error->type = XMPP_SE_UNSUPPORTED_ENCODING;
186 0 : else if (strcmp(name, "unsupported-stanza-type") == 0)
187 0 : conn->stream_error->type = XMPP_SE_UNSUPPORTED_STANZA_TYPE;
188 0 : else if (strcmp(name, "unsupported-version") == 0)
189 0 : conn->stream_error->type = XMPP_SE_UNSUPPORTED_VERSION;
190 0 : else if (strcmp(name, "xml-not-well-formed") == 0)
191 0 : conn->stream_error->type = XMPP_SE_XML_NOT_WELL_FORMED;
192 : }
193 0 : } while ((child = xmpp_stanza_get_next(child)));
194 :
195 0 : conn->stream_error->stanza = xmpp_stanza_clone(stanza);
196 : }
197 :
198 0 : return 1;
199 : }
200 :
201 : /* stream:features handlers */
202 0 : static int _handle_missing_features(xmpp_conn_t *conn, void *userdata)
203 : {
204 0 : UNUSED(userdata);
205 :
206 0 : strophe_debug(conn->ctx, "xmpp", "didn't get stream features");
207 :
208 : /* legacy auth will be attempted */
209 0 : _auth(conn);
210 :
211 0 : return 0;
212 : }
213 :
214 : typedef void (*text_handler)(xmpp_conn_t *conn, const char *text);
215 0 : static void _foreach_child(xmpp_conn_t *conn,
216 : xmpp_stanza_t *parent,
217 : const char *name,
218 : text_handler hndl)
219 : {
220 0 : xmpp_stanza_t *children;
221 0 : for (children = xmpp_stanza_get_children(parent); children;
222 0 : children = xmpp_stanza_get_next(children)) {
223 0 : const char *child_name = xmpp_stanza_get_name(children);
224 0 : if (child_name && strcmp(child_name, name) == 0) {
225 0 : char *text = xmpp_stanza_get_text(children);
226 0 : if (text == NULL)
227 0 : continue;
228 :
229 0 : hndl(conn, text);
230 :
231 0 : strophe_free(conn->ctx, text);
232 : }
233 : }
234 0 : }
235 :
236 0 : static void _handle_sasl_children(xmpp_conn_t *conn, const char *text)
237 : {
238 0 : if (strcasecmp(text, "PLAIN") == 0) {
239 0 : conn->sasl_support |= SASL_MASK_PLAIN;
240 0 : } else if (strcasecmp(text, "EXTERNAL") == 0 &&
241 0 : (conn->tls_client_cert || conn->tls_client_key)) {
242 0 : conn->sasl_support |= SASL_MASK_EXTERNAL;
243 0 : } else if (strcasecmp(text, "DIGEST-MD5") == 0) {
244 0 : conn->sasl_support |= SASL_MASK_DIGESTMD5;
245 0 : } else if (strcasecmp(text, "ANONYMOUS") == 0) {
246 0 : conn->sasl_support |= SASL_MASK_ANONYMOUS;
247 : } else {
248 : size_t n;
249 0 : for (n = 0; n < scram_algs_num; ++n) {
250 0 : if (strcasecmp(text, scram_algs[n]->scram_name) == 0) {
251 0 : conn->sasl_support |= scram_algs[n]->mask;
252 0 : break;
253 : }
254 : }
255 : }
256 0 : }
257 :
258 : static int
259 0 : _handle_features(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
260 : {
261 0 : xmpp_stanza_t *child;
262 :
263 0 : UNUSED(userdata);
264 :
265 : /* remove the handler that detects missing stream:features */
266 0 : xmpp_timed_handler_delete(conn, _handle_missing_features);
267 :
268 : /* check for TLS */
269 0 : if (!conn->secured) {
270 0 : if (!conn->tls_disabled) {
271 0 : if (xmpp_stanza_get_child_by_name_and_ns(stanza, "starttls",
272 : XMPP_NS_TLS)) {
273 0 : conn->tls_support = 1;
274 : }
275 : } else {
276 0 : conn->tls_support = 0;
277 : }
278 : }
279 :
280 : /* check for SASL */
281 0 : child = xmpp_stanza_get_child_by_name_and_ns(stanza, "mechanisms",
282 : XMPP_NS_SASL);
283 0 : if (child) {
284 0 : _foreach_child(conn, child, "mechanism", _handle_sasl_children);
285 : }
286 :
287 : /* Disable PLAIN when other secure mechanisms are supported */
288 0 : if (conn->sasl_support & ~(SASL_MASK_PLAIN | SASL_MASK_ANONYMOUS))
289 0 : conn->sasl_support &= ~SASL_MASK_PLAIN;
290 :
291 0 : _auth(conn);
292 :
293 0 : return 0;
294 : }
295 :
296 : /* returns the correct auth id for a component or a client.
297 : * returned string must be freed by caller */
298 0 : static char *_get_authid(xmpp_conn_t *conn)
299 : {
300 0 : char *authid = NULL;
301 :
302 0 : if (conn->type == XMPP_CLIENT) {
303 : /* authid is the node portion of jid */
304 0 : if (!conn->jid)
305 : return NULL;
306 0 : authid = xmpp_jid_node(conn->ctx, conn->jid);
307 : }
308 :
309 : return authid;
310 : }
311 :
312 0 : static int _handle_proceedtls_default(xmpp_conn_t *conn,
313 : xmpp_stanza_t *stanza,
314 : void *userdata)
315 : {
316 0 : const char *name;
317 :
318 0 : UNUSED(userdata);
319 :
320 0 : name = xmpp_stanza_get_name(stanza);
321 0 : strophe_debug(conn->ctx, "xmpp", "handle proceedtls called for %s", name);
322 :
323 0 : if (strcmp(name, "proceed") == 0) {
324 0 : strophe_debug(conn->ctx, "xmpp", "proceeding with TLS");
325 :
326 0 : if (conn_tls_start(conn) == 0) {
327 0 : conn_prepare_reset(conn, _handle_open_tls);
328 0 : conn_open_stream(conn);
329 : } else {
330 : /* failed tls spoils the connection, so disconnect */
331 0 : xmpp_disconnect(conn);
332 : }
333 : }
334 :
335 0 : return 0;
336 : }
337 :
338 : static int
339 0 : _handle_sasl_result(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
340 : {
341 0 : const char *name;
342 :
343 0 : name = xmpp_stanza_get_name(stanza);
344 :
345 : /* the server should send a <success> or <failure> stanza */
346 0 : if (strcmp(name, "failure") == 0) {
347 0 : strophe_debug(conn->ctx, "xmpp", "SASL %s auth failed",
348 : (char *)userdata);
349 :
350 : /* fall back to next auth method */
351 0 : _auth(conn);
352 0 : } else if (strcmp(name, "success") == 0) {
353 : /* SASL auth successful, we need to restart the stream */
354 0 : strophe_debug(conn->ctx, "xmpp", "SASL %s auth successful",
355 : (char *)userdata);
356 :
357 : /* reset parser */
358 0 : conn_prepare_reset(conn, conn->compression.allowed
359 : ? _handle_open_compress
360 : : _handle_open_sasl);
361 :
362 : /* send stream tag */
363 0 : conn_open_stream(conn);
364 : } else {
365 : /* got unexpected reply */
366 0 : strophe_error(conn->ctx, "xmpp",
367 : "Got unexpected reply to SASL %s authentication.",
368 : (char *)userdata);
369 0 : xmpp_disconnect(conn);
370 : }
371 :
372 0 : return 0;
373 : }
374 :
375 : /* handle the challenge phase of digest auth */
376 0 : static int _handle_digestmd5_challenge(xmpp_conn_t *conn,
377 : xmpp_stanza_t *stanza,
378 : void *userdata)
379 : {
380 0 : char *text;
381 0 : char *response;
382 0 : xmpp_stanza_t *auth, *authdata;
383 0 : const char *name;
384 :
385 0 : UNUSED(userdata);
386 :
387 0 : name = xmpp_stanza_get_name(stanza);
388 0 : strophe_debug(conn->ctx, "xmpp",
389 : "handle digest-md5 (challenge) called for %s", name);
390 :
391 0 : if (strcmp(name, "challenge") == 0) {
392 0 : text = xmpp_stanza_get_text(stanza);
393 0 : response = sasl_digest_md5(conn->ctx, text, conn->jid, conn->pass);
394 0 : if (!response) {
395 0 : disconnect_mem_error(conn);
396 0 : return 0;
397 : }
398 0 : strophe_free(conn->ctx, text);
399 :
400 0 : auth = xmpp_stanza_new(conn->ctx);
401 0 : if (!auth) {
402 0 : disconnect_mem_error(conn);
403 0 : return 0;
404 : }
405 0 : xmpp_stanza_set_name(auth, "response");
406 0 : xmpp_stanza_set_ns(auth, XMPP_NS_SASL);
407 :
408 0 : authdata = xmpp_stanza_new(conn->ctx);
409 0 : if (!authdata) {
410 0 : disconnect_mem_error(conn);
411 0 : return 0;
412 : }
413 :
414 0 : xmpp_stanza_set_text(authdata, response);
415 0 : strophe_free(conn->ctx, response);
416 :
417 0 : xmpp_stanza_add_child_ex(auth, authdata, 0);
418 :
419 0 : handler_add(conn, _handle_digestmd5_rspauth, XMPP_NS_SASL, NULL, NULL,
420 : NULL);
421 :
422 0 : send_stanza(conn, auth, XMPP_QUEUE_STROPHE);
423 :
424 : } else {
425 0 : return _handle_sasl_result(conn, stanza, "DIGEST-MD5");
426 : }
427 :
428 : /* remove ourselves */
429 0 : return 0;
430 : }
431 :
432 : /* handle the rspauth phase of digest auth */
433 0 : static int _handle_digestmd5_rspauth(xmpp_conn_t *conn,
434 : xmpp_stanza_t *stanza,
435 : void *userdata)
436 : {
437 0 : xmpp_stanza_t *auth;
438 0 : const char *name;
439 :
440 0 : UNUSED(userdata);
441 :
442 0 : name = xmpp_stanza_get_name(stanza);
443 0 : strophe_debug(conn->ctx, "xmpp",
444 : "handle digest-md5 (rspauth) called for %s", name);
445 :
446 0 : if (strcmp(name, "challenge") == 0) {
447 : /* assume it's an rspauth response */
448 0 : auth = xmpp_stanza_new(conn->ctx);
449 0 : if (!auth) {
450 0 : disconnect_mem_error(conn);
451 0 : return 0;
452 : }
453 0 : xmpp_stanza_set_name(auth, "response");
454 0 : xmpp_stanza_set_ns(auth, XMPP_NS_SASL);
455 0 : send_stanza(conn, auth, XMPP_QUEUE_STROPHE);
456 : } else {
457 0 : return _handle_sasl_result(conn, stanza, "DIGEST-MD5");
458 : }
459 :
460 0 : return 1;
461 : }
462 :
463 : struct scram_user_data {
464 : xmpp_conn_t *conn;
465 : int sasl_plus;
466 : char *scram_init;
467 : char *channel_binding;
468 : const char *first_bare;
469 : const struct hash_alg *alg;
470 : };
471 :
472 : /* handle the challenge phase of SCRAM-SHA-1 auth */
473 0 : static int _handle_scram_challenge(xmpp_conn_t *conn,
474 : xmpp_stanza_t *stanza,
475 : void *userdata)
476 : {
477 0 : char *text;
478 0 : char *response;
479 0 : xmpp_stanza_t *auth;
480 0 : xmpp_stanza_t *authdata;
481 0 : const char *name;
482 0 : char *challenge;
483 0 : struct scram_user_data *scram_ctx = (struct scram_user_data *)userdata;
484 0 : int rc;
485 :
486 0 : name = xmpp_stanza_get_name(stanza);
487 0 : strophe_debug(conn->ctx, "xmpp", "handle %s (challenge) called for %s",
488 0 : scram_ctx->alg->scram_name, name);
489 :
490 0 : if (strcmp(name, "challenge") == 0) {
491 0 : text = xmpp_stanza_get_text(stanza);
492 0 : if (!text)
493 0 : goto err;
494 :
495 0 : challenge = xmpp_base64_decode_str(conn->ctx, text, strlen(text));
496 0 : strophe_free(conn->ctx, text);
497 0 : if (!challenge)
498 0 : goto err;
499 :
500 0 : response =
501 0 : sasl_scram(conn->ctx, scram_ctx->alg, scram_ctx->channel_binding,
502 0 : challenge, scram_ctx->first_bare, conn->jid, conn->pass);
503 0 : strophe_free(conn->ctx, challenge);
504 0 : if (!response)
505 0 : goto err;
506 :
507 0 : auth = xmpp_stanza_new(conn->ctx);
508 0 : if (!auth)
509 0 : goto err_free_response;
510 0 : xmpp_stanza_set_name(auth, "response");
511 0 : xmpp_stanza_set_ns(auth, XMPP_NS_SASL);
512 :
513 0 : authdata = xmpp_stanza_new(conn->ctx);
514 0 : if (!authdata)
515 0 : goto err_release_auth;
516 0 : xmpp_stanza_set_text(authdata, response);
517 0 : strophe_free(conn->ctx, response);
518 :
519 0 : xmpp_stanza_add_child_ex(auth, authdata, 0);
520 :
521 0 : send_stanza(conn, auth, XMPP_QUEUE_STROPHE);
522 :
523 0 : rc = 1; /* Keep handler */
524 : } else {
525 : /*
526 : * Free scram_ctx after calling _handle_sasl_result(). If authentication
527 : * fails, we want to try other mechanism which may be different SCRAM
528 : * mechanism. If we freed scram_ctx before the function, _auth() would
529 : * be able to allocate new scram_ctx object with the same address and
530 : * handler_add() would consider new SCRAM handler as duplicate, because
531 : * current handler is not removed yet. As result, libstrophe wouldn't
532 : * handle incoming challenge stanza.
533 : */
534 0 : rc = _handle_sasl_result(conn, stanza,
535 0 : (void *)scram_ctx->alg->scram_name);
536 0 : strophe_free_and_null(conn->ctx, scram_ctx->channel_binding);
537 0 : strophe_free_and_null(conn->ctx, scram_ctx->scram_init);
538 0 : strophe_free(conn->ctx, scram_ctx);
539 : }
540 :
541 : return rc;
542 :
543 0 : err_release_auth:
544 0 : xmpp_stanza_release(auth);
545 0 : err_free_response:
546 0 : strophe_free(conn->ctx, response);
547 0 : err:
548 0 : strophe_free_and_null(conn->ctx, scram_ctx->channel_binding);
549 0 : strophe_free_and_null(conn->ctx, scram_ctx->scram_init);
550 0 : strophe_free(conn->ctx, scram_ctx);
551 0 : disconnect_mem_error(conn);
552 0 : return 0;
553 : }
554 :
555 0 : static int _make_scram_init_msg(struct scram_user_data *scram)
556 : {
557 0 : xmpp_conn_t *conn = scram->conn;
558 0 : xmpp_ctx_t *ctx = conn->ctx;
559 0 : const void *binding_data;
560 0 : const char *binding_type;
561 0 : char *node, *message;
562 0 : size_t message_len, binding_type_len = 0, binding_data_len;
563 0 : int l, is_secured = xmpp_conn_is_secured(conn);
564 : /* This buffer must be able to hold:
565 : * "p=<10 bytes binding type>,,<36 bytes binding data>"
566 : * + alignment */
567 0 : char buf[56];
568 :
569 0 : if (scram->sasl_plus) {
570 0 : if (!is_secured) {
571 0 : strophe_error(
572 : ctx, "xmpp",
573 : "SASL: Server requested a -PLUS variant to authenticate, "
574 : "but the connection is not secured. This is an error on "
575 : "the server side we can't do anything about.");
576 0 : return -1;
577 : }
578 0 : if (tls_init_channel_binding(conn->tls, &binding_type,
579 : &binding_type_len)) {
580 : return -1;
581 : }
582 : /* directly account for the '=' char in 'p=<binding-type>' */
583 0 : binding_type_len += 1;
584 : }
585 :
586 0 : node = xmpp_jid_node(ctx, conn->jid);
587 0 : if (!node) {
588 : return -1;
589 : }
590 : /* 32 bytes nonce is enough */
591 0 : xmpp_rand_nonce(ctx->rand, buf, 33);
592 0 : message_len = strlen(node) + strlen(buf) + 8 + binding_type_len + 1;
593 0 : message = strophe_alloc(ctx, message_len);
594 0 : if (!message) {
595 0 : goto err_node;
596 : }
597 : /* increase length to account for 'y,,', 'n,,' or 'p,,'.
598 : * In the 'p' case the '=' sign has already been accounted for above.
599 : */
600 0 : binding_type_len += 3;
601 0 : if (scram->sasl_plus) {
602 0 : l = strophe_snprintf(message, message_len, "p=%s,,n=%s,r=%s",
603 : binding_type, node, buf);
604 : } else {
605 0 : l = strophe_snprintf(message, message_len, "%c,,n=%s,r=%s",
606 : is_secured ? 'y' : 'n', node, buf);
607 : }
608 0 : if (l < 0 || (size_t)l >= message_len) {
609 0 : goto err_msg;
610 : }
611 0 : if (binding_type_len > sizeof(buf)) {
612 0 : goto err_msg;
613 : }
614 : /* Make `first_bare` point to the 'n' of 'n=<node>' of the
615 : * client-first-message */
616 0 : scram->first_bare = message + binding_type_len;
617 0 : memcpy(buf, message, binding_type_len);
618 0 : if (scram->sasl_plus) {
619 0 : binding_data =
620 0 : tls_get_channel_binding_data(conn->tls, &binding_data_len);
621 0 : if (!binding_data) {
622 0 : goto err_msg;
623 : }
624 0 : if (binding_data_len > sizeof(buf) - binding_type_len) {
625 0 : strophe_error(ctx, "xmpp", "Channel binding data is too long (%zu)",
626 : binding_data_len);
627 0 : goto err_msg;
628 : }
629 0 : memcpy(&buf[binding_type_len], binding_data, binding_data_len);
630 0 : binding_type_len += binding_data_len;
631 : }
632 0 : scram->channel_binding =
633 0 : xmpp_base64_encode(ctx, (void *)buf, binding_type_len);
634 0 : memset(buf, 0, binding_type_len);
635 0 : strophe_free(ctx, node);
636 0 : scram->scram_init = message;
637 :
638 0 : return 0;
639 :
640 0 : err_msg:
641 0 : strophe_free(ctx, message);
642 0 : err_node:
643 0 : strophe_free(ctx, node);
644 : return -1;
645 : }
646 :
647 0 : static xmpp_stanza_t *_make_starttls(xmpp_conn_t *conn)
648 : {
649 0 : xmpp_stanza_t *starttls;
650 :
651 : /* build start stanza */
652 0 : starttls = xmpp_stanza_new(conn->ctx);
653 0 : if (starttls) {
654 0 : xmpp_stanza_set_name(starttls, "starttls");
655 0 : xmpp_stanza_set_ns(starttls, XMPP_NS_TLS);
656 : }
657 :
658 0 : return starttls;
659 : }
660 :
661 0 : static xmpp_stanza_t *_make_sasl_auth(xmpp_conn_t *conn, const char *mechanism)
662 : {
663 0 : xmpp_stanza_t *auth;
664 :
665 : /* build auth stanza */
666 0 : auth = xmpp_stanza_new(conn->ctx);
667 0 : if (auth) {
668 0 : xmpp_stanza_set_name(auth, "auth");
669 0 : xmpp_stanza_set_ns(auth, XMPP_NS_SASL);
670 0 : xmpp_stanza_set_attribute(auth, "mechanism", mechanism);
671 : }
672 :
673 0 : return auth;
674 : }
675 :
676 : /* authenticate the connection
677 : * this may get called multiple times. if any auth method fails,
678 : * this will get called again until one auth method succeeds or every
679 : * method fails
680 : */
681 0 : static void _auth(xmpp_conn_t *conn)
682 : {
683 0 : xmpp_stanza_t *auth;
684 0 : xmpp_stanza_t *authdata;
685 0 : struct scram_user_data *scram_ctx;
686 0 : char *authid;
687 0 : char *str;
688 0 : int anonjid;
689 :
690 : /* if there is no node in conn->jid, we assume anonymous connect */
691 0 : str = xmpp_jid_node(conn->ctx, conn->jid);
692 0 : if (str == NULL) {
693 : anonjid = 1;
694 : } else {
695 0 : strophe_free(conn->ctx, str);
696 0 : anonjid = 0;
697 : }
698 :
699 0 : if (conn->tls_support) {
700 0 : tls_t *tls = tls_new(conn);
701 :
702 : /* If we couldn't init tls, it isn't there, so go on */
703 0 : if (!tls) {
704 0 : conn->tls_support = 0;
705 0 : _auth(conn);
706 0 : return;
707 : } else {
708 0 : tls_free(tls);
709 : }
710 :
711 0 : auth = _make_starttls(conn);
712 :
713 0 : if (!auth) {
714 0 : disconnect_mem_error(conn);
715 0 : return;
716 : }
717 :
718 0 : handler_add(conn, _handle_proceedtls_default, XMPP_NS_TLS, NULL, NULL,
719 : NULL);
720 :
721 0 : send_stanza(conn, auth, XMPP_QUEUE_STROPHE);
722 :
723 : /* TLS was tried, unset flag */
724 0 : conn->tls_support = 0;
725 : /* _auth() will be called later */
726 0 : return;
727 : }
728 :
729 0 : if (conn->tls_mandatory && !xmpp_conn_is_secured(conn)) {
730 0 : strophe_error(conn->ctx, "xmpp",
731 : "TLS is not supported, but set as "
732 : "mandatory for this connection");
733 0 : conn_disconnect(conn);
734 0 : return;
735 : }
736 :
737 0 : if (anonjid && (conn->sasl_support & SASL_MASK_ANONYMOUS)) {
738 : /* some crap here */
739 0 : auth = _make_sasl_auth(conn, "ANONYMOUS");
740 0 : if (!auth) {
741 0 : disconnect_mem_error(conn);
742 0 : return;
743 : }
744 :
745 0 : handler_add(conn, _handle_sasl_result, XMPP_NS_SASL, NULL, NULL,
746 : "ANONYMOUS");
747 :
748 0 : send_stanza(conn, auth, XMPP_QUEUE_STROPHE);
749 :
750 : /* SASL ANONYMOUS was tried, unset flag */
751 0 : conn->sasl_support &= ~SASL_MASK_ANONYMOUS;
752 0 : } else if (conn->sasl_support & SASL_MASK_EXTERNAL) {
753 : /* more crap here */
754 0 : auth = _make_sasl_auth(conn, "EXTERNAL");
755 0 : if (!auth) {
756 0 : disconnect_mem_error(conn);
757 0 : return;
758 : }
759 :
760 0 : authdata = xmpp_stanza_new(conn->ctx);
761 0 : if (!authdata) {
762 0 : xmpp_stanza_release(auth);
763 0 : disconnect_mem_error(conn);
764 0 : return;
765 : }
766 0 : str = tls_id_on_xmppaddr(conn, 0);
767 0 : if (!str || (tls_id_on_xmppaddr_num(conn) == 1 &&
768 0 : strcmp(str, conn->jid) == 0)) {
769 0 : xmpp_stanza_set_text(authdata, "=");
770 : } else {
771 0 : strophe_free(conn->ctx, str);
772 0 : str = xmpp_base64_encode(conn->ctx, (void *)conn->jid,
773 : strlen(conn->jid));
774 0 : if (!str) {
775 0 : xmpp_stanza_release(authdata);
776 0 : xmpp_stanza_release(auth);
777 0 : disconnect_mem_error(conn);
778 0 : return;
779 : }
780 0 : xmpp_stanza_set_text(authdata, str);
781 : }
782 0 : strophe_free(conn->ctx, str);
783 :
784 0 : xmpp_stanza_add_child_ex(auth, authdata, 0);
785 :
786 0 : handler_add(conn, _handle_sasl_result, XMPP_NS_SASL, NULL, NULL,
787 : "EXTERNAL");
788 :
789 0 : send_stanza(conn, auth, XMPP_QUEUE_STROPHE);
790 :
791 : /* SASL EXTERNAL was tried, unset flag */
792 0 : conn->sasl_support &= ~SASL_MASK_EXTERNAL;
793 0 : } else if (anonjid) {
794 0 : strophe_error(conn->ctx, "auth",
795 : "No node in JID, and SASL ANONYMOUS unsupported.");
796 0 : xmpp_disconnect(conn);
797 0 : } else if (conn->pass == NULL) {
798 0 : strophe_error(
799 0 : conn->ctx, "auth",
800 : "Password hasn't been set, and SASL ANONYMOUS unsupported.");
801 0 : xmpp_disconnect(conn);
802 0 : } else if (conn->sasl_support & SASL_MASK_SCRAM) {
803 0 : size_t n;
804 0 : scram_ctx = strophe_alloc(conn->ctx, sizeof(*scram_ctx));
805 0 : memset(scram_ctx, 0, sizeof(*scram_ctx));
806 0 : for (n = 0; n < scram_algs_num; ++n) {
807 0 : if (conn->sasl_support & scram_algs[n]->mask) {
808 0 : scram_ctx->alg = scram_algs[n];
809 0 : break;
810 : }
811 : }
812 :
813 0 : auth = _make_sasl_auth(conn, scram_ctx->alg->scram_name);
814 0 : if (!auth) {
815 0 : disconnect_mem_error(conn);
816 0 : return;
817 : }
818 :
819 0 : scram_ctx->conn = conn;
820 0 : scram_ctx->sasl_plus =
821 0 : scram_ctx->alg->mask & SASL_MASK_SCRAM_PLUS ? 1 : 0;
822 0 : if (_make_scram_init_msg(scram_ctx)) {
823 0 : strophe_free(conn->ctx, scram_ctx);
824 0 : xmpp_stanza_release(auth);
825 0 : disconnect_mem_error(conn);
826 0 : return;
827 : }
828 :
829 0 : str = xmpp_base64_encode(conn->ctx,
830 0 : (unsigned char *)scram_ctx->scram_init,
831 : strlen(scram_ctx->scram_init));
832 0 : if (!str) {
833 0 : strophe_free(conn->ctx, scram_ctx->scram_init);
834 0 : strophe_free(conn->ctx, scram_ctx);
835 0 : xmpp_stanza_release(auth);
836 0 : disconnect_mem_error(conn);
837 0 : return;
838 : }
839 :
840 0 : authdata = xmpp_stanza_new(conn->ctx);
841 0 : if (!authdata) {
842 0 : strophe_free(conn->ctx, str);
843 0 : strophe_free(conn->ctx, scram_ctx->scram_init);
844 0 : strophe_free(conn->ctx, scram_ctx);
845 0 : xmpp_stanza_release(auth);
846 0 : disconnect_mem_error(conn);
847 0 : return;
848 : }
849 0 : xmpp_stanza_set_text(authdata, str);
850 0 : strophe_free(conn->ctx, str);
851 0 : xmpp_stanza_add_child_ex(auth, authdata, 0);
852 :
853 0 : handler_add(conn, _handle_scram_challenge, XMPP_NS_SASL, NULL, NULL,
854 : (void *)scram_ctx);
855 :
856 0 : send_stanza(conn, auth, XMPP_QUEUE_STROPHE);
857 :
858 : /* SASL algorithm was tried, unset flag */
859 0 : conn->sasl_support &= ~scram_ctx->alg->mask;
860 0 : } else if (conn->sasl_support & SASL_MASK_DIGESTMD5) {
861 0 : auth = _make_sasl_auth(conn, "DIGEST-MD5");
862 0 : if (!auth) {
863 0 : disconnect_mem_error(conn);
864 0 : return;
865 : }
866 :
867 0 : handler_add(conn, _handle_digestmd5_challenge, XMPP_NS_SASL, NULL, NULL,
868 : NULL);
869 :
870 0 : send_stanza(conn, auth, XMPP_QUEUE_STROPHE);
871 :
872 : /* SASL DIGEST-MD5 was tried, unset flag */
873 0 : conn->sasl_support &= ~SASL_MASK_DIGESTMD5;
874 0 : } else if (conn->sasl_support & SASL_MASK_PLAIN) {
875 0 : auth = _make_sasl_auth(conn, "PLAIN");
876 0 : if (!auth) {
877 0 : disconnect_mem_error(conn);
878 0 : return;
879 : }
880 0 : authdata = xmpp_stanza_new(conn->ctx);
881 0 : if (!authdata) {
882 0 : disconnect_mem_error(conn);
883 0 : return;
884 : }
885 0 : authid = _get_authid(conn);
886 0 : if (!authid) {
887 0 : disconnect_mem_error(conn);
888 0 : return;
889 : }
890 0 : str = sasl_plain(conn->ctx, authid, conn->pass);
891 0 : if (!str) {
892 0 : disconnect_mem_error(conn);
893 0 : return;
894 : }
895 0 : xmpp_stanza_set_text(authdata, str);
896 0 : strophe_free(conn->ctx, str);
897 0 : strophe_free(conn->ctx, authid);
898 :
899 0 : xmpp_stanza_add_child_ex(auth, authdata, 0);
900 :
901 0 : handler_add(conn, _handle_sasl_result, XMPP_NS_SASL, NULL, NULL,
902 : "PLAIN");
903 :
904 0 : send_stanza(conn, auth, XMPP_QUEUE_STROPHE);
905 :
906 : /* SASL PLAIN was tried */
907 0 : conn->sasl_support &= ~SASL_MASK_PLAIN;
908 0 : } else if (conn->type == XMPP_CLIENT && conn->auth_legacy_enabled) {
909 : /* legacy client authentication */
910 0 : _auth_legacy(conn);
911 : } else {
912 0 : strophe_error(conn->ctx, "auth",
913 : "Cannot authenticate with known methods");
914 0 : xmpp_disconnect(conn);
915 : }
916 : }
917 :
918 0 : static void _stream_negotiation_success(xmpp_conn_t *conn)
919 : {
920 0 : tls_clear_password_cache(conn);
921 0 : conn->stream_negotiation_completed = 1;
922 : /* call connection handler */
923 0 : conn->conn_handler(conn, XMPP_CONN_CONNECT, 0, NULL, conn->userdata);
924 0 : }
925 :
926 : /** Set up handlers at stream start.
927 : * This function is called internally to Strophe for handling the opening
928 : * of an XMPP stream. It's called by the parser when a stream is opened
929 : * or reset, and adds the initial handlers for <stream:error/> and
930 : * <stream:features/>. This function is not intended for use outside
931 : * of Strophe.
932 : *
933 : * @param conn a Strophe connection object
934 : */
935 0 : void auth_handle_open(xmpp_conn_t *conn)
936 : {
937 : /* reset all timed handlers */
938 0 : handler_reset_timed(conn, 0);
939 :
940 : /* setup handler for stream:error, we will keep this handler
941 : * for reopened streams until connection is disconnected */
942 0 : handler_add(conn, _handle_error, XMPP_NS_STREAMS, "error", NULL, NULL);
943 :
944 : /* setup handlers for incoming <stream:features> */
945 0 : handler_add(conn, _handle_features, XMPP_NS_STREAMS, "features", NULL,
946 : NULL);
947 0 : handler_add_timed(conn, _handle_missing_features, FEATURES_TIMEOUT, NULL);
948 0 : }
949 :
950 : /* called when stream:stream tag received after TLS establishment */
951 0 : static void _handle_open_tls(xmpp_conn_t *conn)
952 : {
953 : /* setup handlers for incoming <stream:features> */
954 0 : handler_add(conn, _handle_features, XMPP_NS_STREAMS, "features", NULL,
955 : NULL);
956 0 : handler_add_timed(conn, _handle_missing_features, FEATURES_TIMEOUT, NULL);
957 0 : }
958 :
959 : /* called when stream:stream tag received after SASL auth */
960 0 : static void _handle_open_sasl(xmpp_conn_t *conn)
961 : {
962 0 : strophe_debug(conn->ctx, "xmpp", "Reopened stream successfully.");
963 :
964 : /* setup stream:features handlers */
965 0 : handler_add(conn, _handle_features_sasl, XMPP_NS_STREAMS, "features", NULL,
966 : NULL);
967 0 : handler_add_timed(conn, _handle_missing_features_sasl, FEATURES_TIMEOUT,
968 : NULL);
969 0 : }
970 :
971 : /* called when stream:stream tag received after compression has been enabled */
972 0 : static void _handle_open_compress(xmpp_conn_t *conn)
973 : {
974 0 : strophe_debug(conn->ctx, "xmpp", "Reopened stream successfully.");
975 :
976 : /* setup stream:features handlers */
977 0 : handler_add(conn, _handle_features_compress, XMPP_NS_STREAMS, "features",
978 : NULL, NULL);
979 0 : handler_add_timed(conn, _handle_missing_features, FEATURES_TIMEOUT, NULL);
980 0 : }
981 :
982 0 : static int _do_bind(xmpp_conn_t *conn, xmpp_stanza_t *bind)
983 : {
984 0 : xmpp_stanza_t *iq, *res, *text;
985 0 : char *resource;
986 :
987 : /* setup response handlers */
988 0 : handler_add_id(conn, _handle_bind, "_xmpp_bind1", NULL);
989 0 : handler_add_timed(conn, _handle_missing_bind, BIND_TIMEOUT, NULL);
990 :
991 : /* send bind request */
992 0 : iq = xmpp_iq_new(conn->ctx, "set", "_xmpp_bind1");
993 0 : if (!iq) {
994 0 : xmpp_stanza_release(bind);
995 0 : disconnect_mem_error(conn);
996 0 : return 0;
997 : }
998 :
999 : /* request a specific resource if we have one */
1000 0 : resource = xmpp_jid_resource(conn->ctx, conn->jid);
1001 0 : if ((resource != NULL) && (strlen(resource) == 0)) {
1002 : /* jabberd2 doesn't handle an empty resource */
1003 0 : strophe_free(conn->ctx, resource);
1004 0 : resource = NULL;
1005 : }
1006 :
1007 : /* if we have a resource to request, do it. otherwise the
1008 : server will assign us one */
1009 0 : if (resource) {
1010 0 : res = xmpp_stanza_new(conn->ctx);
1011 0 : if (!res) {
1012 0 : xmpp_stanza_release(bind);
1013 0 : xmpp_stanza_release(iq);
1014 0 : disconnect_mem_error(conn);
1015 0 : return 0;
1016 : }
1017 0 : xmpp_stanza_set_name(res, "resource");
1018 0 : text = xmpp_stanza_new(conn->ctx);
1019 0 : if (!text) {
1020 0 : xmpp_stanza_release(res);
1021 0 : xmpp_stanza_release(bind);
1022 0 : xmpp_stanza_release(iq);
1023 0 : disconnect_mem_error(conn);
1024 0 : return 0;
1025 : }
1026 0 : xmpp_stanza_set_text(text, resource);
1027 0 : xmpp_stanza_add_child_ex(res, text, 0);
1028 0 : xmpp_stanza_add_child_ex(bind, res, 0);
1029 0 : strophe_free(conn->ctx, resource);
1030 : }
1031 :
1032 0 : xmpp_stanza_add_child_ex(iq, bind, 0);
1033 :
1034 : /* send bind request */
1035 0 : send_stanza(conn, iq, XMPP_QUEUE_STROPHE);
1036 0 : return 0;
1037 : }
1038 :
1039 0 : static int _handle_compress_result(xmpp_conn_t *const conn,
1040 : xmpp_stanza_t *const stanza,
1041 : void *const userdata)
1042 : {
1043 0 : const char *name = xmpp_stanza_get_name(stanza);
1044 :
1045 0 : UNUSED(userdata);
1046 :
1047 0 : if (!name)
1048 : return 0;
1049 0 : if (strcmp(name, "compressed") == 0) {
1050 : /* Stream compression enabled, we need to restart the stream */
1051 0 : strophe_debug(conn->ctx, "xmpp", "Stream compression enabled");
1052 :
1053 : /* reset parser */
1054 0 : conn_prepare_reset(conn, _handle_open_sasl);
1055 :
1056 : /* make compression effective */
1057 0 : compression_init(conn);
1058 :
1059 : /* send stream tag */
1060 0 : conn_open_stream(conn);
1061 : }
1062 : return 0;
1063 : }
1064 :
1065 0 : static int _handle_features_compress(xmpp_conn_t *conn,
1066 : xmpp_stanza_t *stanza,
1067 : void *userdata)
1068 : {
1069 0 : const char *compress = "<compress xmlns='" XMPP_NS_COMPRESSION
1070 : "'><method>zlib</method></compress>";
1071 0 : xmpp_stanza_t *child;
1072 :
1073 : /* remove missing features handler */
1074 0 : xmpp_timed_handler_delete(conn, _handle_missing_features);
1075 :
1076 : /* check for compression */
1077 0 : child = xmpp_stanza_get_child_by_name_and_ns(stanza, "compression",
1078 : XMPP_NS_FEATURE_COMPRESSION);
1079 0 : if (conn->compression.allowed && child) {
1080 0 : _foreach_child(conn, child, "method",
1081 : compression_handle_feature_children);
1082 : }
1083 :
1084 0 : if (conn->compression.supported) {
1085 0 : send_raw(conn, compress, strlen(compress), XMPP_QUEUE_STROPHE, NULL);
1086 0 : handler_add(conn, _handle_compress_result, XMPP_NS_COMPRESSION, NULL,
1087 : NULL, NULL);
1088 : } else {
1089 0 : return _handle_features_sasl(conn, stanza, userdata);
1090 : }
1091 :
1092 0 : return 0;
1093 : }
1094 :
1095 : static int
1096 0 : _handle_features_sasl(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
1097 : {
1098 0 : xmpp_stanza_t *bind, *session, *opt;
1099 0 : xmpp_stanza_t *resume;
1100 0 : const char *ns;
1101 0 : char h[11];
1102 :
1103 0 : UNUSED(userdata);
1104 :
1105 : /* remove missing features handler */
1106 0 : xmpp_timed_handler_delete(conn, _handle_missing_features_sasl);
1107 :
1108 : /* check whether resource binding is required */
1109 0 : bind = xmpp_stanza_get_child_by_name(stanza, "bind");
1110 0 : if (bind) {
1111 0 : ns = xmpp_stanza_get_ns(bind);
1112 0 : conn->bind_required = ns != NULL && strcmp(ns, XMPP_NS_BIND) == 0;
1113 0 : bind = xmpp_stanza_copy(bind);
1114 0 : if (!bind) {
1115 0 : disconnect_mem_error(conn);
1116 0 : return 0;
1117 : }
1118 : } else {
1119 0 : conn->bind_required = 0;
1120 : }
1121 :
1122 : /* check whether session establishment is required */
1123 0 : session = xmpp_stanza_get_child_by_name(stanza, "session");
1124 0 : if (session) {
1125 0 : ns = xmpp_stanza_get_ns(session);
1126 0 : opt = xmpp_stanza_get_child_by_name(session, "optional");
1127 0 : if (!opt)
1128 0 : conn->session_required =
1129 0 : ns != NULL && strcmp(ns, XMPP_NS_SESSION) == 0;
1130 : }
1131 :
1132 0 : if (xmpp_stanza_get_child_by_name_and_ns(stanza, "sm", XMPP_NS_SM)) {
1133 : /* stream management supported */
1134 0 : conn->sm_state->sm_support = 1;
1135 : }
1136 :
1137 : /* we are expecting either <bind/> and <session/> since this is a
1138 : XMPP style connection or we <resume/> the previous session */
1139 :
1140 : /* check whether we can <resume/> the previous session */
1141 0 : if (!conn->sm_disable && conn->sm_state->can_resume &&
1142 0 : conn->sm_state->previd && conn->sm_state->bound_jid) {
1143 0 : resume = xmpp_stanza_new(conn->ctx);
1144 0 : if (!resume) {
1145 0 : disconnect_mem_error(conn);
1146 0 : return 0;
1147 : }
1148 0 : conn->sm_state->bind = bind;
1149 0 : conn->sm_state->resume = 1;
1150 0 : xmpp_stanza_set_name(resume, "resume");
1151 0 : xmpp_stanza_set_ns(resume, XMPP_NS_SM);
1152 0 : xmpp_stanza_set_attribute(resume, "previd", conn->sm_state->previd);
1153 0 : strophe_snprintf(h, sizeof(h), "%u", conn->sm_state->sm_handled_nr);
1154 0 : xmpp_stanza_set_attribute(resume, "h", h);
1155 0 : send_stanza(conn, resume, XMPP_QUEUE_SM_STROPHE);
1156 0 : handler_add(conn, _handle_sm, XMPP_NS_SM, NULL, NULL, NULL);
1157 : }
1158 : /* if bind is required, go ahead and start it */
1159 0 : else if (conn->bind_required) {
1160 : /* bind resource */
1161 0 : _do_bind(conn, bind);
1162 : } else {
1163 : /* can't bind, disconnect */
1164 0 : if (bind) {
1165 0 : xmpp_stanza_release(bind);
1166 : }
1167 0 : strophe_error(conn->ctx, "xmpp",
1168 : "Stream features does not allow "
1169 : "resource bind.");
1170 0 : xmpp_disconnect(conn);
1171 : }
1172 :
1173 : return 0;
1174 : }
1175 :
1176 0 : static int _handle_missing_features_sasl(xmpp_conn_t *conn, void *userdata)
1177 : {
1178 0 : UNUSED(userdata);
1179 :
1180 0 : strophe_error(conn->ctx, "xmpp",
1181 : "Did not receive stream features "
1182 : "after SASL authentication.");
1183 0 : xmpp_disconnect(conn);
1184 0 : return 0;
1185 : }
1186 :
1187 : static int
1188 0 : _handle_bind(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
1189 : {
1190 0 : const char *type;
1191 0 : xmpp_stanza_t *iq, *session, *binding, *jid_stanza, *enable = NULL;
1192 :
1193 0 : UNUSED(userdata);
1194 :
1195 : /* delete missing bind handler */
1196 0 : xmpp_timed_handler_delete(conn, _handle_missing_bind);
1197 :
1198 : /* server has replied to bind request */
1199 0 : type = xmpp_stanza_get_type(stanza);
1200 0 : if (type && strcmp(type, "error") == 0) {
1201 0 : strophe_error(conn->ctx, "xmpp", "Binding failed.");
1202 0 : xmpp_disconnect(conn);
1203 0 : } else if (type && strcmp(type, "result") == 0) {
1204 0 : binding = xmpp_stanza_get_child_by_name(stanza, "bind");
1205 0 : strophe_debug(conn->ctx, "xmpp", "Bind successful.");
1206 :
1207 0 : if (binding) {
1208 0 : jid_stanza = xmpp_stanza_get_child_by_name(binding, "jid");
1209 0 : if (jid_stanza) {
1210 0 : conn->bound_jid = xmpp_stanza_get_text(jid_stanza);
1211 : }
1212 : }
1213 :
1214 : /* send enable directly after the bind request */
1215 0 : if (conn->sm_state->sm_support && !conn->sm_disable) {
1216 0 : enable = xmpp_stanza_new(conn->ctx);
1217 0 : if (!enable) {
1218 0 : disconnect_mem_error(conn);
1219 0 : return 0;
1220 : }
1221 0 : xmpp_stanza_set_name(enable, "enable");
1222 0 : xmpp_stanza_set_ns(enable, XMPP_NS_SM);
1223 0 : if (!conn->sm_state->dont_request_resume)
1224 0 : xmpp_stanza_set_attribute(enable, "resume", "true");
1225 0 : handler_add(conn, _handle_sm, XMPP_NS_SM, NULL, NULL, NULL);
1226 0 : send_stanza(conn, enable, XMPP_QUEUE_SM_STROPHE);
1227 0 : conn->sm_state->sm_sent_nr = 0;
1228 0 : conn->sm_state->sm_enabled = 1;
1229 : }
1230 :
1231 : /* establish a session if required */
1232 0 : if (conn->session_required) {
1233 : /* setup response handlers */
1234 0 : handler_add_id(conn, _handle_session, "_xmpp_session1", NULL);
1235 0 : handler_add_timed(conn, _handle_missing_session, SESSION_TIMEOUT,
1236 : NULL);
1237 :
1238 : /* send session request */
1239 0 : iq = xmpp_iq_new(conn->ctx, "set", "_xmpp_session1");
1240 0 : if (!iq) {
1241 0 : disconnect_mem_error(conn);
1242 0 : return 0;
1243 : }
1244 :
1245 0 : session = xmpp_stanza_new(conn->ctx);
1246 0 : if (!session) {
1247 0 : xmpp_stanza_release(iq);
1248 0 : disconnect_mem_error(conn);
1249 0 : return 0;
1250 : }
1251 :
1252 0 : xmpp_stanza_set_name(session, "session");
1253 0 : xmpp_stanza_set_ns(session, XMPP_NS_SESSION);
1254 :
1255 0 : xmpp_stanza_add_child_ex(iq, session, 0);
1256 :
1257 : /* send session establishment request */
1258 0 : send_stanza(conn, iq, XMPP_QUEUE_STROPHE);
1259 : }
1260 :
1261 : /* if there's no xmpp session required and we didn't try to enable
1262 : * stream-management, we're done here and the stream-negotiation was
1263 : * successful
1264 : */
1265 0 : if (!conn->session_required && !enable) {
1266 0 : _stream_negotiation_success(conn);
1267 : }
1268 : } else {
1269 0 : strophe_error(conn->ctx, "xmpp", "Server sent malformed bind reply.");
1270 0 : xmpp_disconnect(conn);
1271 : }
1272 :
1273 : return 0;
1274 : }
1275 :
1276 0 : static int _handle_missing_bind(xmpp_conn_t *conn, void *userdata)
1277 : {
1278 0 : UNUSED(userdata);
1279 :
1280 0 : strophe_error(conn->ctx, "xmpp", "Server did not reply to bind request.");
1281 0 : xmpp_disconnect(conn);
1282 0 : return 0;
1283 : }
1284 :
1285 : static int
1286 0 : _handle_session(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
1287 : {
1288 0 : const char *type;
1289 :
1290 0 : UNUSED(userdata);
1291 :
1292 : /* delete missing session handler */
1293 0 : xmpp_timed_handler_delete(conn, _handle_missing_session);
1294 :
1295 : /* server has replied to the session request */
1296 0 : type = xmpp_stanza_get_type(stanza);
1297 0 : if (type && strcmp(type, "error") == 0) {
1298 0 : strophe_error(conn->ctx, "xmpp", "Session establishment failed.");
1299 0 : xmpp_disconnect(conn);
1300 0 : } else if (type && strcmp(type, "result") == 0) {
1301 0 : strophe_debug(conn->ctx, "xmpp", "Session establishment successful.");
1302 :
1303 0 : _stream_negotiation_success(conn);
1304 : } else {
1305 0 : strophe_error(conn->ctx, "xmpp",
1306 : "Server sent malformed session reply.");
1307 0 : xmpp_disconnect(conn);
1308 : }
1309 :
1310 0 : return 0;
1311 : }
1312 :
1313 0 : static int _handle_missing_session(xmpp_conn_t *conn, void *userdata)
1314 : {
1315 0 : UNUSED(userdata);
1316 :
1317 0 : strophe_error(conn->ctx, "xmpp",
1318 : "Server did not reply to session request.");
1319 0 : xmpp_disconnect(conn);
1320 0 : return 0;
1321 : }
1322 :
1323 0 : static int _handle_missing_legacy(xmpp_conn_t *conn, void *userdata)
1324 : {
1325 0 : UNUSED(userdata);
1326 :
1327 0 : strophe_error(conn->ctx, "xmpp",
1328 : "Server did not reply to legacy "
1329 : "authentication request.");
1330 0 : xmpp_disconnect(conn);
1331 0 : return 0;
1332 : }
1333 :
1334 0 : static int _get_h_attribute(xmpp_stanza_t *stanza, unsigned long *ul_h)
1335 : {
1336 0 : const char *h = xmpp_stanza_get_attribute(stanza, "h");
1337 0 : if (!h || string_to_ul(h, ul_h)) {
1338 0 : strophe_error(
1339 0 : stanza->ctx, "xmpp",
1340 : "SM error: failed parsing 'h', \"%s\" got converted to %llu.",
1341 : STR_MAYBE_NULL(h), *ul_h);
1342 0 : return -1;
1343 : }
1344 : return 0;
1345 : }
1346 :
1347 0 : static void _sm_queue_cleanup(xmpp_conn_t *conn, unsigned long ul_h)
1348 : {
1349 0 : xmpp_send_queue_t *e;
1350 0 : while ((e = peek_queue_front(&conn->sm_state->sm_queue))) {
1351 0 : if (e->sm_h >= ul_h)
1352 : break;
1353 0 : e = pop_queue_front(&conn->sm_state->sm_queue);
1354 0 : strophe_free(conn->ctx, queue_element_free(conn->ctx, e));
1355 : }
1356 0 : }
1357 :
1358 0 : static void _sm_queue_resend(xmpp_conn_t *conn)
1359 : {
1360 0 : xmpp_send_queue_t *e;
1361 0 : while ((e = pop_queue_front(&conn->sm_state->sm_queue))) {
1362 : /* Re-send what was already sent out and is still in the
1363 : * SM queue (i.e. it hasn't been ACK'ed by the server)
1364 : */
1365 0 : strophe_debug_verbose(2, conn->ctx, "conn", "SM_Q_RESEND: %p, h=%lu", e,
1366 : e->sm_h);
1367 0 : send_raw(conn, e->data, e->len, e->owner, NULL);
1368 0 : strophe_free(conn->ctx, queue_element_free(conn->ctx, e));
1369 : }
1370 0 : }
1371 :
1372 0 : static int _handle_sm(xmpp_conn_t *const conn,
1373 : xmpp_stanza_t *const stanza,
1374 : void *const userdata)
1375 : {
1376 0 : xmpp_stanza_t *failed_cause, *bind = NULL;
1377 0 : const char *name, *id, *previd, *resume, *cause;
1378 0 : unsigned long ul_h = 0;
1379 :
1380 0 : UNUSED(userdata);
1381 :
1382 0 : name = xmpp_stanza_get_name(stanza);
1383 0 : if (!name)
1384 0 : goto err_sm;
1385 :
1386 0 : if (strcmp(name, "enabled") == 0) {
1387 0 : conn->sm_state->sm_handled_nr = 0;
1388 0 : resume = xmpp_stanza_get_attribute(stanza, "resume");
1389 0 : if (resume && (strcasecmp(resume, "true") || strcmp(resume, "1"))) {
1390 0 : id = xmpp_stanza_get_attribute(stanza, "id");
1391 0 : if (!id) {
1392 0 : strophe_error(conn->ctx, "xmpp",
1393 : "SM error: server said it can resume, but "
1394 : "didn't provide an ID.");
1395 0 : name = NULL;
1396 0 : goto err_sm;
1397 : }
1398 0 : conn->sm_state->can_resume = 1;
1399 0 : conn->sm_state->id = strophe_strdup(conn->ctx, id);
1400 : }
1401 : /* We maybe have stuff in the SM queue if we tried to resume, but the
1402 : * server doesn't remember all details of our session, but the `h` was
1403 : * still available.
1404 : */
1405 0 : _sm_queue_resend(conn);
1406 0 : _stream_negotiation_success(conn);
1407 0 : } else if (strcmp(name, "resumed") == 0) {
1408 0 : previd = xmpp_stanza_get_attribute(stanza, "previd");
1409 0 : if (!previd || strcmp(previd, conn->sm_state->previd)) {
1410 0 : strophe_error(conn->ctx, "xmpp",
1411 : "SM error: previd didn't match, ours is \"%s\".",
1412 0 : conn->sm_state->previd);
1413 0 : name = NULL;
1414 0 : goto err_sm;
1415 : }
1416 0 : if (_get_h_attribute(stanza, &ul_h)) {
1417 0 : name = NULL;
1418 0 : goto err_sm;
1419 : }
1420 0 : conn->sm_state->sm_enabled = 1;
1421 0 : conn->sm_state->id = conn->sm_state->previd;
1422 0 : conn->sm_state->previd = NULL;
1423 0 : conn->bound_jid = conn->sm_state->bound_jid;
1424 0 : conn->sm_state->bound_jid = NULL;
1425 0 : if (conn->sm_state->sm_queue.head)
1426 0 : conn->sm_state->sm_sent_nr = conn->sm_state->sm_queue.head->sm_h;
1427 : else
1428 0 : conn->sm_state->sm_sent_nr = ul_h;
1429 0 : _sm_queue_cleanup(conn, ul_h);
1430 0 : _sm_queue_resend(conn);
1431 0 : strophe_debug(conn->ctx, "xmpp", "Session resumed successfully.");
1432 0 : _stream_negotiation_success(conn);
1433 0 : } else if (strcmp(name, "failed") == 0) {
1434 0 : name = NULL;
1435 0 : conn->sm_state->sm_enabled = 0;
1436 :
1437 0 : failed_cause =
1438 0 : xmpp_stanza_get_child_by_ns(stanza, XMPP_NS_STANZAS_IETF);
1439 0 : if (!failed_cause)
1440 0 : goto err_sm;
1441 :
1442 0 : cause = xmpp_stanza_get_name(failed_cause);
1443 0 : if (!cause)
1444 0 : goto err_sm;
1445 :
1446 0 : if (!strcmp(cause, "item-not-found")) {
1447 0 : if (conn->sm_state->resume) {
1448 : /* It's no error if there's no `h` attribute included
1449 : * but if there is, it gives a hint at what the server
1450 : * already received.
1451 : */
1452 0 : if (!_get_h_attribute(stanza, &ul_h)) {
1453 : /* In cases there's no `h` included, drop all elements. */
1454 0 : ul_h = (unsigned long)-1;
1455 : }
1456 0 : _sm_queue_cleanup(conn, ul_h);
1457 : }
1458 0 : } else if (!strcmp(cause, "feature-not-implemented")) {
1459 0 : conn->sm_state->resume = 0;
1460 0 : conn->sm_state->can_resume = 0;
1461 : /* remember that the server reports having support
1462 : * for resumption, but actually it doesn't ...
1463 : */
1464 0 : conn->sm_state->dont_request_resume = 1;
1465 : }
1466 0 : bind = conn->sm_state->bind;
1467 0 : conn->sm_state->bind = NULL;
1468 0 : reset_sm_state(conn->sm_state);
1469 0 : _do_bind(conn, bind);
1470 : } else {
1471 : /* unknown stanza received */
1472 : name = NULL;
1473 : }
1474 :
1475 : err_sm:
1476 0 : if (!name) {
1477 0 : char *err = "Couldn't convert stanza to text!";
1478 0 : char *buf;
1479 0 : size_t buflen;
1480 0 : switch (xmpp_stanza_to_text(stanza, &buf, &buflen)) {
1481 : case XMPP_EOK:
1482 : break;
1483 0 : case XMPP_EMEM:
1484 0 : disconnect_mem_error(conn);
1485 0 : return 0;
1486 0 : default:
1487 0 : buf = err;
1488 0 : break;
1489 : }
1490 0 : strophe_warn(conn->ctx, "xmpp", "SM error: Stanza received was: %s",
1491 : buf);
1492 0 : if (buf != err)
1493 0 : strophe_free(conn->ctx, buf);
1494 : /* Don't disable for <failure> cases, they're no hard errors */
1495 0 : conn->sm_state->sm_enabled = bind != NULL;
1496 : }
1497 : return 0;
1498 : }
1499 :
1500 : static int
1501 0 : _handle_legacy(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
1502 : {
1503 0 : const char *type;
1504 0 : const char *name;
1505 :
1506 0 : UNUSED(userdata);
1507 :
1508 : /* delete missing handler */
1509 0 : xmpp_timed_handler_delete(conn, _handle_missing_legacy);
1510 :
1511 : /* server responded to legacy auth request */
1512 0 : type = xmpp_stanza_get_type(stanza);
1513 0 : name = xmpp_stanza_get_name(stanza);
1514 0 : if (!type || strcmp(name, "iq") != 0) {
1515 0 : strophe_error(conn->ctx, "xmpp",
1516 : "Server sent us an unexpected response "
1517 : "to legacy authentication request.");
1518 0 : xmpp_disconnect(conn);
1519 0 : } else if (strcmp(type, "error") == 0) {
1520 : /* legacy client auth failed, no more fallbacks */
1521 0 : strophe_error(conn->ctx, "xmpp",
1522 : "Legacy client authentication failed.");
1523 0 : xmpp_disconnect(conn);
1524 0 : } else if (strcmp(type, "result") == 0) {
1525 : /* auth succeeded */
1526 0 : strophe_debug(conn->ctx, "xmpp", "Legacy auth succeeded.");
1527 :
1528 0 : _stream_negotiation_success(conn);
1529 : } else {
1530 0 : strophe_error(conn->ctx, "xmpp",
1531 : "Server sent us a legacy authentication "
1532 : "response with a bad type.");
1533 0 : xmpp_disconnect(conn);
1534 : }
1535 :
1536 0 : return 0;
1537 : }
1538 :
1539 0 : static void _auth_legacy(xmpp_conn_t *conn)
1540 : {
1541 0 : xmpp_stanza_t *iq;
1542 0 : xmpp_stanza_t *authdata;
1543 0 : xmpp_stanza_t *query;
1544 0 : xmpp_stanza_t *child;
1545 0 : char *str;
1546 :
1547 0 : strophe_debug(conn->ctx, "auth", "Legacy authentication request");
1548 :
1549 0 : iq = xmpp_iq_new(conn->ctx, "set", "_xmpp_auth1");
1550 0 : if (!iq)
1551 0 : goto err;
1552 :
1553 0 : query = xmpp_stanza_new(conn->ctx);
1554 0 : if (!query)
1555 0 : goto err_free;
1556 0 : xmpp_stanza_set_name(query, "query");
1557 0 : xmpp_stanza_set_ns(query, XMPP_NS_AUTH);
1558 0 : xmpp_stanza_add_child_ex(iq, query, 0);
1559 :
1560 0 : child = xmpp_stanza_new(conn->ctx);
1561 0 : if (!child)
1562 0 : goto err_free;
1563 0 : xmpp_stanza_set_name(child, "username");
1564 0 : xmpp_stanza_add_child_ex(query, child, 0);
1565 :
1566 0 : authdata = xmpp_stanza_new(conn->ctx);
1567 0 : if (!authdata)
1568 0 : goto err_free;
1569 0 : str = xmpp_jid_node(conn->ctx, conn->jid);
1570 0 : if (!str) {
1571 0 : xmpp_stanza_release(authdata);
1572 0 : goto err_free;
1573 : }
1574 0 : xmpp_stanza_set_text(authdata, str);
1575 0 : strophe_free(conn->ctx, str);
1576 0 : xmpp_stanza_add_child_ex(child, authdata, 0);
1577 :
1578 0 : child = xmpp_stanza_new(conn->ctx);
1579 0 : if (!child)
1580 0 : goto err_free;
1581 0 : xmpp_stanza_set_name(child, "password");
1582 0 : xmpp_stanza_add_child_ex(query, child, 0);
1583 :
1584 0 : authdata = xmpp_stanza_new(conn->ctx);
1585 0 : if (!authdata)
1586 0 : goto err_free;
1587 0 : xmpp_stanza_set_text(authdata, conn->pass);
1588 0 : xmpp_stanza_add_child_ex(child, authdata, 0);
1589 :
1590 0 : child = xmpp_stanza_new(conn->ctx);
1591 0 : if (!child)
1592 0 : goto err_free;
1593 0 : xmpp_stanza_set_name(child, "resource");
1594 0 : xmpp_stanza_add_child_ex(query, child, 0);
1595 :
1596 0 : authdata = xmpp_stanza_new(conn->ctx);
1597 0 : if (!authdata)
1598 0 : goto err_free;
1599 0 : str = xmpp_jid_resource(conn->ctx, conn->jid);
1600 0 : if (str) {
1601 0 : xmpp_stanza_set_text(authdata, str);
1602 0 : strophe_free(conn->ctx, str);
1603 : } else {
1604 0 : xmpp_stanza_release(authdata);
1605 0 : xmpp_stanza_release(iq);
1606 0 : strophe_error(conn->ctx, "auth",
1607 : "Cannot authenticate without resource");
1608 0 : xmpp_disconnect(conn);
1609 0 : return;
1610 : }
1611 0 : xmpp_stanza_add_child_ex(child, authdata, 0);
1612 :
1613 0 : handler_add_id(conn, _handle_legacy, "_xmpp_auth1", NULL);
1614 0 : handler_add_timed(conn, _handle_missing_legacy, LEGACY_TIMEOUT, NULL);
1615 :
1616 0 : send_stanza(conn, iq, XMPP_QUEUE_STROPHE);
1617 0 : return;
1618 :
1619 0 : err_free:
1620 0 : xmpp_stanza_release(iq);
1621 0 : err:
1622 0 : disconnect_mem_error(conn);
1623 : }
1624 :
1625 0 : void auth_handle_component_open(xmpp_conn_t *conn)
1626 : {
1627 0 : int rc;
1628 :
1629 : /* reset all timed handlers */
1630 0 : handler_reset_timed(conn, 0);
1631 :
1632 0 : handler_add(conn, _handle_error, XMPP_NS_STREAMS, "error", NULL, NULL);
1633 0 : handler_add(conn, _handle_component_hs_response, NULL, "handshake", NULL,
1634 : NULL);
1635 0 : handler_add_timed(conn, _handle_missing_handshake, HANDSHAKE_TIMEOUT, NULL);
1636 :
1637 0 : rc = _handle_component_auth(conn);
1638 0 : if (rc != 0) {
1639 0 : strophe_error(conn->ctx, "auth", "Component authentication failed.");
1640 0 : xmpp_disconnect(conn);
1641 : }
1642 0 : }
1643 :
1644 : /* Will compute SHA1 and authenticate the component to the server */
1645 0 : int _handle_component_auth(xmpp_conn_t *conn)
1646 : {
1647 0 : uint8_t md_value[SHA1_DIGEST_SIZE];
1648 0 : SHA1_CTX mdctx;
1649 0 : char *digest;
1650 0 : size_t i;
1651 :
1652 0 : if (conn->stream_id == NULL) {
1653 0 : strophe_error(conn->ctx, "auth",
1654 : "Received no stream id from the server.");
1655 0 : return XMPP_EINT;
1656 : }
1657 :
1658 : /* Feed the session id and passphrase to the algorithm.
1659 : * We need to compute SHA1(session_id + passphrase)
1660 : */
1661 0 : crypto_SHA1_Init(&mdctx);
1662 0 : crypto_SHA1_Update(&mdctx, (uint8_t *)conn->stream_id,
1663 : strlen(conn->stream_id));
1664 0 : crypto_SHA1_Update(&mdctx, (uint8_t *)conn->pass, strlen(conn->pass));
1665 0 : crypto_SHA1_Final(&mdctx, md_value);
1666 :
1667 0 : digest = strophe_alloc(conn->ctx, 2 * sizeof(md_value) + 1);
1668 0 : if (digest) {
1669 : /* convert the digest into string representation */
1670 0 : for (i = 0; i < sizeof(md_value); i++)
1671 0 : strophe_snprintf(digest + i * 2, 3, "%02x", md_value[i]);
1672 0 : digest[2 * sizeof(md_value)] = '\0';
1673 :
1674 0 : strophe_debug(conn->ctx, "auth", "Digest: %s, len: %d", digest,
1675 : strlen(digest));
1676 :
1677 : /* Send the digest to the server */
1678 0 : send_raw_string(conn, "<handshake xmlns='%s'>%s</handshake>",
1679 : XMPP_NS_COMPONENT, digest);
1680 0 : strophe_debug(conn->ctx, "auth",
1681 : "Sent component handshake to the server.");
1682 0 : strophe_free(conn->ctx, digest);
1683 : } else {
1684 0 : strophe_debug(conn->ctx, "auth",
1685 : "Couldn't allocate memory for component "
1686 : "handshake digest.");
1687 0 : return XMPP_EMEM;
1688 : }
1689 :
1690 : return 0;
1691 : }
1692 :
1693 : /* Check if the received stanza is <handshake/> and set auth to true
1694 : * and fire connection handler.
1695 : */
1696 0 : int _handle_component_hs_response(xmpp_conn_t *conn,
1697 : xmpp_stanza_t *stanza,
1698 : void *userdata)
1699 : {
1700 0 : const char *name;
1701 :
1702 0 : UNUSED(userdata);
1703 :
1704 0 : xmpp_timed_handler_delete(conn, _handle_missing_handshake);
1705 :
1706 0 : name = xmpp_stanza_get_name(stanza);
1707 0 : if (strcmp(name, "handshake") != 0) {
1708 0 : char *msg;
1709 0 : size_t msg_size;
1710 0 : xmpp_stanza_to_text(stanza, &msg, &msg_size);
1711 0 : if (msg) {
1712 0 : strophe_debug(conn->ctx, "auth", "Handshake failed: %s", msg);
1713 0 : strophe_free(conn->ctx, msg);
1714 : }
1715 0 : xmpp_disconnect(conn);
1716 0 : return XMPP_EINT;
1717 : } else {
1718 0 : _stream_negotiation_success(conn);
1719 : }
1720 :
1721 : /* We don't need this handler anymore, return 0 so it can be deleted
1722 : * from the list of handlers.
1723 : */
1724 0 : return 0;
1725 : }
1726 :
1727 0 : int _handle_missing_handshake(xmpp_conn_t *conn, void *userdata)
1728 : {
1729 0 : UNUSED(userdata);
1730 :
1731 0 : strophe_error(conn->ctx, "xmpp",
1732 : "Server did not reply to handshake request.");
1733 0 : xmpp_disconnect(conn);
1734 0 : return 0;
1735 : }
1736 :
1737 0 : void auth_handle_open_raw(xmpp_conn_t *conn)
1738 : {
1739 0 : handler_reset_timed(conn, 0);
1740 : /* user handlers are not called before stream negotiation has completed. */
1741 0 : _stream_negotiation_success(conn);
1742 0 : }
1743 :
1744 0 : void auth_handle_open_stub(xmpp_conn_t *conn)
1745 : {
1746 0 : strophe_warn(conn->ctx, "auth", "Stub callback is called.");
1747 0 : }
|