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 0 : 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 : (unsigned char *)scram_ctx->scram_init,
831 0 : 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;
1099 0 : xmpp_stanza_t *resume;
1100 0 : char h[11];
1101 :
1102 0 : UNUSED(userdata);
1103 :
1104 : /* Remove missing features handler */
1105 0 : xmpp_timed_handler_delete(conn, _handle_missing_features_sasl);
1106 :
1107 : /* Check whether resource binding is required */
1108 0 : bind = xmpp_stanza_get_child_by_name_and_ns(stanza, "bind", XMPP_NS_BIND);
1109 0 : if (bind) {
1110 0 : conn->bind_required = 1;
1111 0 : bind = xmpp_stanza_copy(bind);
1112 0 : if (!bind) {
1113 0 : disconnect_mem_error(conn);
1114 0 : return 0;
1115 : }
1116 : } else {
1117 0 : conn->bind_required = 0;
1118 : }
1119 :
1120 : /* Check whether session establishment is required.
1121 : *
1122 : * The mechanism is deprecated, but we still support it.
1123 : *
1124 : * RFC3921 contains Ch. 3 "Session Establishment".
1125 : *
1126 : * RFC6121 removes this and explains in Ch. 1.4:
1127 : * "Interoperability Note: [...] Implementation and deployment experience
1128 : * has shown that this additional step is unnecessary. [...]" */
1129 0 : session = xmpp_stanza_get_child_by_name_and_ns(stanza, "session",
1130 : XMPP_NS_SESSION);
1131 0 : if (session) {
1132 0 : conn->session_required =
1133 0 : xmpp_stanza_get_child_by_name(session, "optional") == NULL;
1134 : }
1135 :
1136 : /* Check stream-management support */
1137 0 : if (xmpp_stanza_get_child_by_name_and_ns(stanza, "sm", XMPP_NS_SM)) {
1138 0 : conn->sm_state->sm_support = 1;
1139 : }
1140 :
1141 : /* We are expecting either <bind/> and optionally <session/> since this is a
1142 : XMPP style connection or we <resume/> the previous session */
1143 :
1144 : /* Check whether we can <resume/> the previous session */
1145 0 : if (!conn->sm_disable && conn->sm_state->can_resume &&
1146 0 : conn->sm_state->previd && conn->sm_state->bound_jid) {
1147 0 : resume = xmpp_stanza_new(conn->ctx);
1148 0 : if (!resume) {
1149 0 : disconnect_mem_error(conn);
1150 0 : return 0;
1151 : }
1152 0 : conn->sm_state->bind = bind;
1153 0 : conn->sm_state->resume = 1;
1154 0 : xmpp_stanza_set_name(resume, "resume");
1155 0 : xmpp_stanza_set_ns(resume, XMPP_NS_SM);
1156 0 : xmpp_stanza_set_attribute(resume, "previd", conn->sm_state->previd);
1157 0 : strophe_snprintf(h, sizeof(h), "%u", conn->sm_state->sm_handled_nr);
1158 0 : xmpp_stanza_set_attribute(resume, "h", h);
1159 0 : send_stanza(conn, resume, XMPP_QUEUE_SM_STROPHE);
1160 0 : handler_add(conn, _handle_sm, XMPP_NS_SM, NULL, NULL, NULL);
1161 : }
1162 : /* if bind is required, go ahead and start it */
1163 0 : else if (conn->bind_required) {
1164 : /* bind resource */
1165 0 : _do_bind(conn, bind);
1166 : } else {
1167 : /* can't bind, disconnect */
1168 0 : if (bind) {
1169 0 : xmpp_stanza_release(bind);
1170 : }
1171 0 : strophe_error(conn->ctx, "xmpp",
1172 : "Stream features does not allow "
1173 : "resource bind.");
1174 0 : xmpp_disconnect(conn);
1175 : }
1176 :
1177 : return 0;
1178 : }
1179 :
1180 0 : static int _handle_missing_features_sasl(xmpp_conn_t *conn, void *userdata)
1181 : {
1182 0 : UNUSED(userdata);
1183 :
1184 0 : strophe_error(conn->ctx, "xmpp",
1185 : "Did not receive stream features "
1186 : "after SASL authentication.");
1187 0 : xmpp_disconnect(conn);
1188 0 : return 0;
1189 : }
1190 :
1191 0 : static void _session_start(xmpp_conn_t *conn)
1192 : {
1193 0 : xmpp_stanza_t *session;
1194 0 : xmpp_stanza_t *iq = xmpp_iq_new(conn->ctx, "set", "_xmpp_session1");
1195 0 : if (!iq) {
1196 0 : disconnect_mem_error(conn);
1197 0 : return;
1198 : }
1199 :
1200 0 : session = xmpp_stanza_new(conn->ctx);
1201 0 : if (!session) {
1202 0 : xmpp_stanza_release(iq);
1203 0 : disconnect_mem_error(conn);
1204 0 : return;
1205 : }
1206 :
1207 : /* setup response handlers */
1208 0 : handler_add_id(conn, _handle_session, "_xmpp_session1", NULL);
1209 0 : handler_add_timed(conn, _handle_missing_session, SESSION_TIMEOUT, NULL);
1210 :
1211 0 : xmpp_stanza_set_name(session, "session");
1212 0 : xmpp_stanza_set_ns(session, XMPP_NS_SESSION);
1213 :
1214 0 : xmpp_stanza_add_child_ex(iq, session, 0);
1215 :
1216 : /* send session establishment request */
1217 0 : send_stanza(conn, iq, XMPP_QUEUE_STROPHE);
1218 : }
1219 :
1220 0 : static void _sm_enable(xmpp_conn_t *conn)
1221 : {
1222 0 : xmpp_stanza_t *enable = xmpp_stanza_new(conn->ctx);
1223 0 : if (!enable) {
1224 0 : disconnect_mem_error(conn);
1225 0 : return;
1226 : }
1227 0 : xmpp_stanza_set_name(enable, "enable");
1228 0 : xmpp_stanza_set_ns(enable, XMPP_NS_SM);
1229 0 : if (!conn->sm_state->dont_request_resume)
1230 0 : xmpp_stanza_set_attribute(enable, "resume", "true");
1231 0 : handler_add(conn, _handle_sm, XMPP_NS_SM, NULL, NULL, NULL);
1232 0 : send_stanza(conn, enable, XMPP_QUEUE_SM_STROPHE);
1233 0 : conn->sm_state->sm_sent_nr = 0;
1234 0 : conn->sm_state->sm_enabled = 1;
1235 : }
1236 :
1237 : static int
1238 0 : _handle_bind(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
1239 : {
1240 0 : const char *type;
1241 0 : xmpp_stanza_t *binding, *jid_stanza;
1242 :
1243 0 : UNUSED(userdata);
1244 :
1245 : /* delete missing bind handler */
1246 0 : xmpp_timed_handler_delete(conn, _handle_missing_bind);
1247 :
1248 : /* server has replied to bind request */
1249 0 : type = xmpp_stanza_get_type(stanza);
1250 0 : if (type && strcmp(type, "error") == 0) {
1251 0 : strophe_error(conn->ctx, "xmpp", "Binding failed.");
1252 0 : xmpp_disconnect(conn);
1253 0 : } else if (type && strcmp(type, "result") == 0) {
1254 0 : binding = xmpp_stanza_get_child_by_name(stanza, "bind");
1255 0 : strophe_debug(conn->ctx, "xmpp", "Bind successful.");
1256 :
1257 0 : if (binding) {
1258 0 : jid_stanza = xmpp_stanza_get_child_by_name(binding, "jid");
1259 0 : if (jid_stanza) {
1260 0 : conn->bound_jid = xmpp_stanza_get_text(jid_stanza);
1261 : }
1262 : }
1263 :
1264 : /* establish a session if required */
1265 0 : if (conn->session_required) {
1266 0 : _session_start(conn);
1267 : }
1268 : /* send enable directly after the bind request */
1269 0 : else if (conn->sm_state->sm_support && !conn->sm_disable) {
1270 0 : _sm_enable(conn);
1271 : }
1272 : /* if there's no xmpp session required and we didn't try to enable
1273 : * stream-management, we're done here and the stream-negotiation was
1274 : * successful
1275 : */
1276 : else {
1277 0 : _stream_negotiation_success(conn);
1278 : }
1279 : } else {
1280 0 : strophe_error(conn->ctx, "xmpp", "Server sent malformed bind reply.");
1281 0 : xmpp_disconnect(conn);
1282 : }
1283 :
1284 0 : return 0;
1285 : }
1286 :
1287 0 : static int _handle_missing_bind(xmpp_conn_t *conn, void *userdata)
1288 : {
1289 0 : UNUSED(userdata);
1290 :
1291 0 : strophe_error(conn->ctx, "xmpp", "Server did not reply to bind request.");
1292 0 : xmpp_disconnect(conn);
1293 0 : return 0;
1294 : }
1295 :
1296 : static int
1297 0 : _handle_session(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
1298 : {
1299 0 : const char *type;
1300 :
1301 0 : UNUSED(userdata);
1302 :
1303 : /* delete missing session handler */
1304 0 : xmpp_timed_handler_delete(conn, _handle_missing_session);
1305 :
1306 : /* server has replied to the session request */
1307 0 : type = xmpp_stanza_get_type(stanza);
1308 0 : if (type && strcmp(type, "error") == 0) {
1309 0 : strophe_error(conn->ctx, "xmpp", "Session establishment failed.");
1310 0 : xmpp_disconnect(conn);
1311 0 : } else if (type && strcmp(type, "result") == 0) {
1312 0 : strophe_debug(conn->ctx, "xmpp", "Session establishment successful.");
1313 0 : if (conn->sm_state->sm_support && !conn->sm_disable) {
1314 0 : _sm_enable(conn);
1315 : } else {
1316 0 : _stream_negotiation_success(conn);
1317 : }
1318 : } else {
1319 0 : strophe_error(conn->ctx, "xmpp",
1320 : "Server sent malformed session reply.");
1321 0 : xmpp_disconnect(conn);
1322 : }
1323 :
1324 0 : return 0;
1325 : }
1326 :
1327 0 : static int _handle_missing_session(xmpp_conn_t *conn, void *userdata)
1328 : {
1329 0 : UNUSED(userdata);
1330 :
1331 0 : strophe_error(conn->ctx, "xmpp",
1332 : "Server did not reply to session request.");
1333 0 : xmpp_disconnect(conn);
1334 0 : return 0;
1335 : }
1336 :
1337 0 : static int _handle_missing_legacy(xmpp_conn_t *conn, void *userdata)
1338 : {
1339 0 : UNUSED(userdata);
1340 :
1341 0 : strophe_error(conn->ctx, "xmpp",
1342 : "Server did not reply to legacy "
1343 : "authentication request.");
1344 0 : xmpp_disconnect(conn);
1345 0 : return 0;
1346 : }
1347 :
1348 0 : static int _get_h_attribute(xmpp_stanza_t *stanza, unsigned long *ul_h)
1349 : {
1350 0 : const char *h = xmpp_stanza_get_attribute(stanza, "h");
1351 0 : if (!h || string_to_ul(h, ul_h)) {
1352 0 : strophe_error(
1353 0 : stanza->ctx, "xmpp",
1354 : "SM error: failed parsing 'h', \"%s\" got converted to %llu.",
1355 : STR_MAYBE_NULL(h), *ul_h);
1356 0 : return -1;
1357 : }
1358 : return 0;
1359 : }
1360 :
1361 0 : static void _sm_queue_cleanup(xmpp_conn_t *conn, unsigned long ul_h)
1362 : {
1363 0 : xmpp_send_queue_t *e;
1364 0 : while ((e = peek_queue_front(&conn->sm_state->sm_queue))) {
1365 0 : if (e->sm_h >= ul_h)
1366 : break;
1367 0 : e = pop_queue_front(&conn->sm_state->sm_queue);
1368 0 : strophe_free(conn->ctx, queue_element_free(conn->ctx, e));
1369 : }
1370 0 : }
1371 :
1372 0 : static void _sm_queue_resend(xmpp_conn_t *conn)
1373 : {
1374 0 : xmpp_send_queue_t *e;
1375 0 : while ((e = pop_queue_front(&conn->sm_state->sm_queue))) {
1376 : /* Re-send what was already sent out and is still in the
1377 : * SM queue (i.e. it hasn't been ACK'ed by the server)
1378 : */
1379 0 : strophe_debug_verbose(2, conn->ctx, "conn", "SM_Q_RESEND: %p, h=%lu", e,
1380 : e->sm_h);
1381 0 : send_raw(conn, e->data, e->len, e->owner, NULL);
1382 0 : strophe_free(conn->ctx, queue_element_free(conn->ctx, e));
1383 : }
1384 0 : }
1385 :
1386 0 : static int _handle_sm(xmpp_conn_t *const conn,
1387 : xmpp_stanza_t *const stanza,
1388 : void *const userdata)
1389 : {
1390 0 : xmpp_stanza_t *failed_cause, *bind = NULL;
1391 0 : const char *name, *id, *previd, *resume, *cause;
1392 0 : unsigned long ul_h = 0;
1393 :
1394 0 : UNUSED(userdata);
1395 :
1396 0 : name = xmpp_stanza_get_name(stanza);
1397 0 : if (!name)
1398 0 : goto err_sm;
1399 :
1400 0 : if (strcmp(name, "enabled") == 0) {
1401 0 : conn->sm_state->sm_handled_nr = 0;
1402 0 : resume = xmpp_stanza_get_attribute(stanza, "resume");
1403 0 : if (resume && (strcasecmp(resume, "true") || strcmp(resume, "1"))) {
1404 0 : id = xmpp_stanza_get_attribute(stanza, "id");
1405 0 : if (!id) {
1406 0 : strophe_error(conn->ctx, "xmpp",
1407 : "SM error: server said it can resume, but "
1408 : "didn't provide an ID.");
1409 0 : name = NULL;
1410 0 : goto err_sm;
1411 : }
1412 0 : conn->sm_state->can_resume = 1;
1413 0 : conn->sm_state->id = strophe_strdup(conn->ctx, id);
1414 : }
1415 : /* We maybe have stuff in the SM queue if we tried to resume, but the
1416 : * server doesn't remember all details of our session, but the `h` was
1417 : * still available.
1418 : */
1419 0 : _sm_queue_resend(conn);
1420 0 : _stream_negotiation_success(conn);
1421 0 : } else if (strcmp(name, "resumed") == 0) {
1422 0 : previd = xmpp_stanza_get_attribute(stanza, "previd");
1423 0 : if (!previd || strcmp(previd, conn->sm_state->previd)) {
1424 0 : strophe_error(conn->ctx, "xmpp",
1425 : "SM error: previd didn't match, ours is \"%s\".",
1426 0 : conn->sm_state->previd);
1427 0 : name = NULL;
1428 0 : goto err_sm;
1429 : }
1430 0 : if (_get_h_attribute(stanza, &ul_h)) {
1431 0 : name = NULL;
1432 0 : goto err_sm;
1433 : }
1434 0 : conn->sm_state->sm_enabled = 1;
1435 0 : conn->sm_state->id = conn->sm_state->previd;
1436 0 : conn->sm_state->previd = NULL;
1437 0 : conn->bound_jid = conn->sm_state->bound_jid;
1438 0 : conn->sm_state->bound_jid = NULL;
1439 0 : if (conn->sm_state->sm_queue.head)
1440 0 : conn->sm_state->sm_sent_nr = conn->sm_state->sm_queue.head->sm_h;
1441 : else
1442 0 : conn->sm_state->sm_sent_nr = ul_h;
1443 0 : _sm_queue_cleanup(conn, ul_h);
1444 0 : _sm_queue_resend(conn);
1445 0 : strophe_debug(conn->ctx, "xmpp", "Session resumed successfully.");
1446 0 : _stream_negotiation_success(conn);
1447 0 : } else if (strcmp(name, "failed") == 0) {
1448 0 : name = NULL;
1449 0 : conn->sm_state->sm_enabled = 0;
1450 :
1451 0 : failed_cause =
1452 0 : xmpp_stanza_get_child_by_ns(stanza, XMPP_NS_STANZAS_IETF);
1453 0 : if (!failed_cause)
1454 0 : goto err_sm;
1455 :
1456 0 : cause = xmpp_stanza_get_name(failed_cause);
1457 0 : if (!cause)
1458 0 : goto err_sm;
1459 :
1460 0 : if (!strcmp(cause, "item-not-found")) {
1461 0 : if (conn->sm_state->resume) {
1462 : /* It's no error if there's no `h` attribute included
1463 : * but if there is, it gives a hint at what the server
1464 : * already received.
1465 : */
1466 0 : if (!_get_h_attribute(stanza, &ul_h)) {
1467 : /* In cases there's no `h` included, drop all elements. */
1468 0 : ul_h = (unsigned long)-1;
1469 : }
1470 0 : _sm_queue_cleanup(conn, ul_h);
1471 : }
1472 0 : } else if (!strcmp(cause, "feature-not-implemented")) {
1473 0 : conn->sm_state->resume = 0;
1474 0 : conn->sm_state->can_resume = 0;
1475 : /* remember that the server reports having support
1476 : * for resumption, but actually it doesn't ...
1477 : */
1478 0 : conn->sm_state->dont_request_resume = 1;
1479 : }
1480 0 : bind = conn->sm_state->bind;
1481 0 : conn->sm_state->bind = NULL;
1482 0 : reset_sm_state(conn->sm_state);
1483 0 : _do_bind(conn, bind);
1484 : } else {
1485 : /* unknown stanza received */
1486 : name = NULL;
1487 : }
1488 :
1489 : err_sm:
1490 0 : if (!name) {
1491 0 : char *err = "Couldn't convert stanza to text!";
1492 0 : char *buf;
1493 0 : size_t buflen;
1494 0 : switch (xmpp_stanza_to_text(stanza, &buf, &buflen)) {
1495 : case XMPP_EOK:
1496 : break;
1497 0 : case XMPP_EMEM:
1498 0 : disconnect_mem_error(conn);
1499 0 : return 0;
1500 0 : default:
1501 0 : buf = err;
1502 0 : break;
1503 : }
1504 0 : strophe_warn(conn->ctx, "xmpp", "SM error: Stanza received was: %s",
1505 : buf);
1506 0 : if (buf != err)
1507 0 : strophe_free(conn->ctx, buf);
1508 : /* Don't disable for <failure> cases, they're no hard errors */
1509 0 : conn->sm_state->sm_enabled = bind != NULL;
1510 : }
1511 : return 0;
1512 : }
1513 :
1514 : static int
1515 0 : _handle_legacy(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
1516 : {
1517 0 : const char *type;
1518 0 : const char *name;
1519 :
1520 0 : UNUSED(userdata);
1521 :
1522 : /* delete missing handler */
1523 0 : xmpp_timed_handler_delete(conn, _handle_missing_legacy);
1524 :
1525 : /* server responded to legacy auth request */
1526 0 : type = xmpp_stanza_get_type(stanza);
1527 0 : name = xmpp_stanza_get_name(stanza);
1528 0 : if (!type || strcmp(name, "iq") != 0) {
1529 0 : strophe_error(conn->ctx, "xmpp",
1530 : "Server sent us an unexpected response "
1531 : "to legacy authentication request.");
1532 0 : xmpp_disconnect(conn);
1533 0 : } else if (strcmp(type, "error") == 0) {
1534 : /* legacy client auth failed, no more fallbacks */
1535 0 : strophe_error(conn->ctx, "xmpp",
1536 : "Legacy client authentication failed.");
1537 0 : xmpp_disconnect(conn);
1538 0 : } else if (strcmp(type, "result") == 0) {
1539 : /* auth succeeded */
1540 0 : strophe_debug(conn->ctx, "xmpp", "Legacy auth succeeded.");
1541 :
1542 0 : _stream_negotiation_success(conn);
1543 : } else {
1544 0 : strophe_error(conn->ctx, "xmpp",
1545 : "Server sent us a legacy authentication "
1546 : "response with a bad type.");
1547 0 : xmpp_disconnect(conn);
1548 : }
1549 :
1550 0 : return 0;
1551 : }
1552 :
1553 0 : static void _auth_legacy(xmpp_conn_t *conn)
1554 : {
1555 0 : xmpp_stanza_t *iq;
1556 0 : xmpp_stanza_t *authdata;
1557 0 : xmpp_stanza_t *query;
1558 0 : xmpp_stanza_t *child;
1559 0 : char *str;
1560 :
1561 0 : strophe_debug(conn->ctx, "auth", "Legacy authentication request");
1562 :
1563 0 : iq = xmpp_iq_new(conn->ctx, "set", "_xmpp_auth1");
1564 0 : if (!iq)
1565 0 : goto err;
1566 :
1567 0 : query = xmpp_stanza_new(conn->ctx);
1568 0 : if (!query)
1569 0 : goto err_free;
1570 0 : xmpp_stanza_set_name(query, "query");
1571 0 : xmpp_stanza_set_ns(query, XMPP_NS_AUTH);
1572 0 : xmpp_stanza_add_child_ex(iq, query, 0);
1573 :
1574 0 : child = xmpp_stanza_new(conn->ctx);
1575 0 : if (!child)
1576 0 : goto err_free;
1577 0 : xmpp_stanza_set_name(child, "username");
1578 0 : xmpp_stanza_add_child_ex(query, child, 0);
1579 :
1580 0 : authdata = xmpp_stanza_new(conn->ctx);
1581 0 : if (!authdata)
1582 0 : goto err_free;
1583 0 : str = xmpp_jid_node(conn->ctx, conn->jid);
1584 0 : if (!str) {
1585 0 : xmpp_stanza_release(authdata);
1586 0 : goto err_free;
1587 : }
1588 0 : xmpp_stanza_set_text(authdata, str);
1589 0 : strophe_free(conn->ctx, str);
1590 0 : xmpp_stanza_add_child_ex(child, authdata, 0);
1591 :
1592 0 : child = xmpp_stanza_new(conn->ctx);
1593 0 : if (!child)
1594 0 : goto err_free;
1595 0 : xmpp_stanza_set_name(child, "password");
1596 0 : xmpp_stanza_add_child_ex(query, child, 0);
1597 :
1598 0 : authdata = xmpp_stanza_new(conn->ctx);
1599 0 : if (!authdata)
1600 0 : goto err_free;
1601 0 : xmpp_stanza_set_text(authdata, conn->pass);
1602 0 : xmpp_stanza_add_child_ex(child, authdata, 0);
1603 :
1604 0 : child = xmpp_stanza_new(conn->ctx);
1605 0 : if (!child)
1606 0 : goto err_free;
1607 0 : xmpp_stanza_set_name(child, "resource");
1608 0 : xmpp_stanza_add_child_ex(query, child, 0);
1609 :
1610 0 : authdata = xmpp_stanza_new(conn->ctx);
1611 0 : if (!authdata)
1612 0 : goto err_free;
1613 0 : str = xmpp_jid_resource(conn->ctx, conn->jid);
1614 0 : if (str) {
1615 0 : xmpp_stanza_set_text(authdata, str);
1616 0 : strophe_free(conn->ctx, str);
1617 : } else {
1618 0 : xmpp_stanza_release(authdata);
1619 0 : xmpp_stanza_release(iq);
1620 0 : strophe_error(conn->ctx, "auth",
1621 : "Cannot authenticate without resource");
1622 0 : xmpp_disconnect(conn);
1623 0 : return;
1624 : }
1625 0 : xmpp_stanza_add_child_ex(child, authdata, 0);
1626 :
1627 0 : handler_add_id(conn, _handle_legacy, "_xmpp_auth1", NULL);
1628 0 : handler_add_timed(conn, _handle_missing_legacy, LEGACY_TIMEOUT, NULL);
1629 :
1630 0 : send_stanza(conn, iq, XMPP_QUEUE_STROPHE);
1631 0 : return;
1632 :
1633 0 : err_free:
1634 0 : xmpp_stanza_release(iq);
1635 0 : err:
1636 0 : disconnect_mem_error(conn);
1637 : }
1638 :
1639 0 : void auth_handle_component_open(xmpp_conn_t *conn)
1640 : {
1641 0 : int rc;
1642 :
1643 : /* reset all timed handlers */
1644 0 : handler_reset_timed(conn, 0);
1645 :
1646 0 : handler_add(conn, _handle_error, XMPP_NS_STREAMS, "error", NULL, NULL);
1647 0 : handler_add(conn, _handle_component_hs_response, NULL, "handshake", NULL,
1648 : NULL);
1649 0 : handler_add_timed(conn, _handle_missing_handshake, HANDSHAKE_TIMEOUT, NULL);
1650 :
1651 0 : rc = _handle_component_auth(conn);
1652 0 : if (rc != 0) {
1653 0 : strophe_error(conn->ctx, "auth", "Component authentication failed.");
1654 0 : xmpp_disconnect(conn);
1655 : }
1656 0 : }
1657 :
1658 : /* Will compute SHA1 and authenticate the component to the server */
1659 0 : int _handle_component_auth(xmpp_conn_t *conn)
1660 : {
1661 0 : uint8_t md_value[SHA1_DIGEST_SIZE];
1662 0 : SHA1_CTX mdctx;
1663 0 : char *digest;
1664 0 : size_t i;
1665 :
1666 0 : if (conn->stream_id == NULL) {
1667 0 : strophe_error(conn->ctx, "auth",
1668 : "Received no stream id from the server.");
1669 0 : return XMPP_EINT;
1670 : }
1671 :
1672 : /* Feed the session id and passphrase to the algorithm.
1673 : * We need to compute SHA1(session_id + passphrase)
1674 : */
1675 0 : crypto_SHA1_Init(&mdctx);
1676 0 : crypto_SHA1_Update(&mdctx, (uint8_t *)conn->stream_id,
1677 0 : strlen(conn->stream_id));
1678 0 : crypto_SHA1_Update(&mdctx, (uint8_t *)conn->pass, strlen(conn->pass));
1679 0 : crypto_SHA1_Final(&mdctx, md_value);
1680 :
1681 0 : digest = strophe_alloc(conn->ctx, 2 * sizeof(md_value) + 1);
1682 0 : if (digest) {
1683 : /* convert the digest into string representation */
1684 0 : for (i = 0; i < sizeof(md_value); i++)
1685 0 : strophe_snprintf(digest + i * 2, 3, "%02x", md_value[i]);
1686 0 : digest[2 * sizeof(md_value)] = '\0';
1687 :
1688 0 : strophe_debug(conn->ctx, "auth", "Digest: %s, len: %d", digest,
1689 : strlen(digest));
1690 :
1691 : /* Send the digest to the server */
1692 0 : send_raw_string(conn, "<handshake xmlns='%s'>%s</handshake>",
1693 : XMPP_NS_COMPONENT, digest);
1694 0 : strophe_debug(conn->ctx, "auth",
1695 : "Sent component handshake to the server.");
1696 0 : strophe_free(conn->ctx, digest);
1697 : } else {
1698 0 : strophe_debug(conn->ctx, "auth",
1699 : "Couldn't allocate memory for component "
1700 : "handshake digest.");
1701 0 : return XMPP_EMEM;
1702 : }
1703 :
1704 : return 0;
1705 : }
1706 :
1707 : /* Check if the received stanza is <handshake/> and set auth to true
1708 : * and fire connection handler.
1709 : */
1710 0 : int _handle_component_hs_response(xmpp_conn_t *conn,
1711 : xmpp_stanza_t *stanza,
1712 : void *userdata)
1713 : {
1714 0 : const char *name;
1715 :
1716 0 : UNUSED(userdata);
1717 :
1718 0 : xmpp_timed_handler_delete(conn, _handle_missing_handshake);
1719 :
1720 0 : name = xmpp_stanza_get_name(stanza);
1721 0 : if (strcmp(name, "handshake") != 0) {
1722 0 : char *msg;
1723 0 : size_t msg_size;
1724 0 : xmpp_stanza_to_text(stanza, &msg, &msg_size);
1725 0 : if (msg) {
1726 0 : strophe_debug(conn->ctx, "auth", "Handshake failed: %s", msg);
1727 0 : strophe_free(conn->ctx, msg);
1728 : }
1729 0 : xmpp_disconnect(conn);
1730 0 : return XMPP_EINT;
1731 : } else {
1732 0 : _stream_negotiation_success(conn);
1733 : }
1734 :
1735 : /* We don't need this handler anymore, return 0 so it can be deleted
1736 : * from the list of handlers.
1737 : */
1738 0 : return 0;
1739 : }
1740 :
1741 0 : int _handle_missing_handshake(xmpp_conn_t *conn, void *userdata)
1742 : {
1743 0 : UNUSED(userdata);
1744 :
1745 0 : strophe_error(conn->ctx, "xmpp",
1746 : "Server did not reply to handshake request.");
1747 0 : xmpp_disconnect(conn);
1748 0 : return 0;
1749 : }
1750 :
1751 0 : void auth_handle_open_raw(xmpp_conn_t *conn)
1752 : {
1753 0 : handler_reset_timed(conn, 0);
1754 : /* user handlers are not called before stream negotiation has completed. */
1755 0 : _stream_negotiation_success(conn);
1756 0 : }
1757 :
1758 0 : void auth_handle_open_stub(xmpp_conn_t *conn)
1759 : {
1760 0 : strophe_warn(conn->ctx, "auth", "Stub callback is called.");
1761 0 : }
|