yong-stropheruby 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/.autotest +9 -0
- data/History.txt +4 -0
- data/Manifest.txt +39 -0
- data/PostInstall.txt +4 -0
- data/README.rdoc +143 -0
- data/Rakefile +21 -0
- data/ext/auth.c +990 -0
- data/ext/common.h +287 -0
- data/ext/conn.c +609 -0
- data/ext/ctx.c +416 -0
- data/ext/event.c +345 -0
- data/ext/extconf.rb +6 -0
- data/ext/handler.c +592 -0
- data/ext/hash.c +278 -0
- data/ext/hash.h +64 -0
- data/ext/jid.c +177 -0
- data/ext/md5.c +289 -0
- data/ext/md5.h +41 -0
- data/ext/ostypes.h +27 -0
- data/ext/parser.c +206 -0
- data/ext/sasl.c +614 -0
- data/ext/sasl.h +44 -0
- data/ext/sha1.c +389 -0
- data/ext/sha1.h +31 -0
- data/ext/snprintf.c +839 -0
- data/ext/sock.c +911 -0
- data/ext/sock.h +51 -0
- data/ext/stanza.c +908 -0
- data/ext/strophe.h +372 -0
- data/ext/strophe_ruby.c +687 -0
- data/ext/thread.c +119 -0
- data/ext/thread.h +43 -0
- data/ext/tls.h +46 -0
- data/ext/tls_dummy.c +89 -0
- data/ext/util.c +107 -0
- data/ext/util.h +32 -0
- data/lib/strophe_ruby.rb +6 -0
- data/test/test_helper.rb +3 -0
- data/test/test_strophe_ruby.rb +11 -0
- data/test/test_strophe_ruby_extn.rb +9 -0
- metadata +108 -0
data/ext/auth.c
ADDED
@@ -0,0 +1,990 @@
|
|
1
|
+
/* auth.c
|
2
|
+
** strophe XMPP client library -- auth functions and handlers
|
3
|
+
**
|
4
|
+
** Copyright (C) 2005-2008 OGG, LLC. All rights reserved.
|
5
|
+
**
|
6
|
+
** This software is provided AS-IS with no warranty, either express or
|
7
|
+
** implied.
|
8
|
+
**
|
9
|
+
** This software is distributed under license and may not be copied,
|
10
|
+
** modified or distributed except as expressly authorized under the
|
11
|
+
** terms of the license contained in the file LICENSE.txt in this
|
12
|
+
** distribution.
|
13
|
+
*/
|
14
|
+
|
15
|
+
/** @file
|
16
|
+
* Authentication function and handlers.
|
17
|
+
*/
|
18
|
+
|
19
|
+
#include <stdio.h>
|
20
|
+
#include <stdlib.h>
|
21
|
+
#include <string.h>
|
22
|
+
|
23
|
+
#include "strophe.h"
|
24
|
+
#include "common.h"
|
25
|
+
#include "sasl.h"
|
26
|
+
|
27
|
+
#ifdef _WIN32
|
28
|
+
#define strcasecmp stricmp
|
29
|
+
#endif
|
30
|
+
|
31
|
+
/* TODO: these should configurable at runtime on a per connection basis */
|
32
|
+
|
33
|
+
#ifndef FEATURES_TIMEOUT
|
34
|
+
/** @def FEATURES_TIMEOUT
|
35
|
+
* Time to wait for <stream:features/> stanza.
|
36
|
+
*/
|
37
|
+
#define FEATURES_TIMEOUT 15000 /* 15 seconds */
|
38
|
+
#endif
|
39
|
+
#ifndef BIND_TIMEOUT
|
40
|
+
/** @def BIND_TIMEOUT
|
41
|
+
* Time to wait for <bind/> stanza reply.
|
42
|
+
*/
|
43
|
+
#define BIND_TIMEOUT 15000 /* 15 seconds */
|
44
|
+
#endif
|
45
|
+
#ifndef SESSION_TIMEOUT
|
46
|
+
/** @def SESSION_TIMEOUT
|
47
|
+
* Time to wait for <session/> stanza reply.
|
48
|
+
*/
|
49
|
+
#define SESSION_TIMEOUT 15000 /* 15 seconds */
|
50
|
+
#endif
|
51
|
+
#ifndef LEGACY_TIMEOUT
|
52
|
+
/** @def LEGACY_TIMEOUT
|
53
|
+
* Time to wait for legacy authentication to complete.
|
54
|
+
*/
|
55
|
+
#define LEGACY_TIMEOUT 15000 /* 15 seconds */
|
56
|
+
#endif
|
57
|
+
|
58
|
+
static void _auth(xmpp_conn_t * const conn);
|
59
|
+
static void _handle_open_tls(xmpp_conn_t * const conn);
|
60
|
+
static void _handle_open_sasl(xmpp_conn_t * const conn);
|
61
|
+
static int _handle_missing_legacy(xmpp_conn_t * const conn,
|
62
|
+
void * const userdata);
|
63
|
+
static int _handle_legacy(xmpp_conn_t * const conn,
|
64
|
+
xmpp_stanza_t * const stanza,
|
65
|
+
void * const userdata);
|
66
|
+
static int _handle_features_sasl(xmpp_conn_t * const conn,
|
67
|
+
xmpp_stanza_t * const stanza,
|
68
|
+
void * const userdata);
|
69
|
+
static int _handle_sasl_result(xmpp_conn_t * const conn,
|
70
|
+
xmpp_stanza_t * const stanza,
|
71
|
+
void * const userdata);
|
72
|
+
static int _handle_digestmd5_challenge(xmpp_conn_t * const conn,
|
73
|
+
xmpp_stanza_t * const stanza,
|
74
|
+
void * const userdata);
|
75
|
+
static int _handle_digestmd5_rspauth(xmpp_conn_t * const conn,
|
76
|
+
xmpp_stanza_t * const stanza,
|
77
|
+
void * const userdata);
|
78
|
+
|
79
|
+
static int _handle_missing_features_sasl(xmpp_conn_t * const conn,
|
80
|
+
void * const userdata);
|
81
|
+
static int _handle_missing_bind(xmpp_conn_t * const conn,
|
82
|
+
void * const userdata);
|
83
|
+
static int _handle_bind(xmpp_conn_t * const conn,
|
84
|
+
xmpp_stanza_t * const stanza,
|
85
|
+
void * const userdata);
|
86
|
+
static int _handle_session(xmpp_conn_t * const conn,
|
87
|
+
xmpp_stanza_t * const stanza,
|
88
|
+
void * const userdata);
|
89
|
+
static int _handle_missing_session(xmpp_conn_t * const conn,
|
90
|
+
void * const userdata);
|
91
|
+
|
92
|
+
/* stream:error handler */
|
93
|
+
static int _handle_error(xmpp_conn_t * const conn,
|
94
|
+
xmpp_stanza_t * const stanza,
|
95
|
+
void * const userdata)
|
96
|
+
{
|
97
|
+
xmpp_stanza_t *child;
|
98
|
+
char *name;
|
99
|
+
|
100
|
+
/* free old stream error if it's still there */
|
101
|
+
if (conn->stream_error) {
|
102
|
+
xmpp_stanza_release(conn->stream_error->stanza);
|
103
|
+
if (conn->stream_error->text)
|
104
|
+
xmpp_free(conn->ctx, conn->stream_error->text);
|
105
|
+
xmpp_free(conn->ctx, conn->stream_error);
|
106
|
+
}
|
107
|
+
|
108
|
+
/* create stream error structure */
|
109
|
+
conn->stream_error = (xmpp_stream_error_t *)xmpp_alloc(conn->ctx, sizeof(xmpp_stream_error_t));
|
110
|
+
|
111
|
+
conn->stream_error->text = NULL;
|
112
|
+
conn->stream_error->type = XMPP_SE_UNDEFINED_CONDITION;
|
113
|
+
|
114
|
+
if (conn->stream_error) {
|
115
|
+
child = xmpp_stanza_get_children(stanza);
|
116
|
+
do {
|
117
|
+
char *ns = NULL;
|
118
|
+
|
119
|
+
if (child) {
|
120
|
+
ns = xmpp_stanza_get_ns(child);
|
121
|
+
}
|
122
|
+
|
123
|
+
if (ns && strcmp(ns, XMPP_NS_STREAMS_IETF) == 0) {
|
124
|
+
name = xmpp_stanza_get_name(child);
|
125
|
+
if (strcmp(name, "text") == 0) {
|
126
|
+
if (conn->stream_error->text)
|
127
|
+
xmpp_free(conn->ctx, conn->stream_error->text);
|
128
|
+
conn->stream_error->text = xmpp_stanza_get_text(child);
|
129
|
+
} else if (strcmp(name, "bad-format") == 0)
|
130
|
+
conn->stream_error->type = XMPP_SE_BAD_FORMAT;
|
131
|
+
else if (strcmp(name, "bad-namespace-prefix") == 0)
|
132
|
+
conn->stream_error->type = XMPP_SE_BAD_NS_PREFIX;
|
133
|
+
else if (strcmp(name, "conflict") == 0)
|
134
|
+
conn->stream_error->type = XMPP_SE_CONFLICT;
|
135
|
+
else if (strcmp(name, "connection-timeout") == 0)
|
136
|
+
conn->stream_error->type = XMPP_SE_CONN_TIMEOUT;
|
137
|
+
else if (strcmp(name, "host-gone") == 0)
|
138
|
+
conn->stream_error->type = XMPP_SE_HOST_GONE;
|
139
|
+
else if (strcmp(name, "host-unknown") == 0)
|
140
|
+
conn->stream_error->type = XMPP_SE_HOST_UNKNOWN;
|
141
|
+
else if (strcmp(name, "improper-addressing") == 0)
|
142
|
+
conn->stream_error->type = XMPP_SE_IMPROPER_ADDR;
|
143
|
+
else if (strcmp(name, "internal-server-error") == 0)
|
144
|
+
conn->stream_error->type = XMPP_SE_INTERNAL_SERVER_ERROR;
|
145
|
+
else if (strcmp(name, "invalid-from") == 0)
|
146
|
+
conn->stream_error->type = XMPP_SE_INVALID_FROM;
|
147
|
+
else if (strcmp(name, "invalid-id") == 0)
|
148
|
+
conn->stream_error->type = XMPP_SE_INVALID_ID;
|
149
|
+
else if (strcmp(name, "invalid-namespace") == 0)
|
150
|
+
conn->stream_error->type = XMPP_SE_INVALID_NS;
|
151
|
+
else if (strcmp(name, "invalid-xml") == 0)
|
152
|
+
conn->stream_error->type = XMPP_SE_INVALID_XML;
|
153
|
+
else if (strcmp(name, "not-authorized") == 0)
|
154
|
+
conn->stream_error->type = XMPP_SE_NOT_AUTHORIZED;
|
155
|
+
else if (strcmp(name, "policy-violation") == 0)
|
156
|
+
conn->stream_error->type = XMPP_SE_POLICY_VIOLATION;
|
157
|
+
else if (strcmp(name, "remote-connection-failed") == 0)
|
158
|
+
conn->stream_error->type = XMPP_SE_REMOTE_CONN_FAILED;
|
159
|
+
else if (strcmp(name, "resource-constraint") == 0)
|
160
|
+
conn->stream_error->type = XMPP_SE_RESOURCE_CONSTRAINT;
|
161
|
+
else if (strcmp(name, "restricted-xml") == 0)
|
162
|
+
conn->stream_error->type = XMPP_SE_RESTRICTED_XML;
|
163
|
+
else if (strcmp(name, "see-other-host") == 0)
|
164
|
+
conn->stream_error->type = XMPP_SE_SEE_OTHER_HOST;
|
165
|
+
else if (strcmp(name, "system-shutdown") == 0)
|
166
|
+
conn->stream_error->type = XMPP_SE_SYSTEM_SHUTDOWN;
|
167
|
+
else if (strcmp(name, "undefined-condition") == 0)
|
168
|
+
conn->stream_error->type = XMPP_SE_UNDEFINED_CONDITION;
|
169
|
+
else if (strcmp(name, "unsupported-encoding") == 0)
|
170
|
+
conn->stream_error->type = XMPP_SE_UNSUPPORTED_ENCODING;
|
171
|
+
else if (strcmp(name, "unsupported-stanza-type") == 0)
|
172
|
+
conn->stream_error->type = XMPP_SE_UNSUPPORTED_STANZA_TYPE;
|
173
|
+
else if (strcmp(name, "unsupported-version") == 0)
|
174
|
+
conn->stream_error->type = XMPP_SE_UNSUPPORTED_VERSION;
|
175
|
+
else if (strcmp(name, "xml-not-well-formed") == 0)
|
176
|
+
conn->stream_error->type = XMPP_SE_XML_NOT_WELL_FORMED;
|
177
|
+
}
|
178
|
+
} while ((child = xmpp_stanza_get_next(child)));
|
179
|
+
|
180
|
+
conn->stream_error->stanza = xmpp_stanza_clone(stanza);
|
181
|
+
}
|
182
|
+
|
183
|
+
return 1;
|
184
|
+
}
|
185
|
+
|
186
|
+
/* stream:features handlers */
|
187
|
+
static int _handle_missing_features(xmpp_conn_t * const conn,
|
188
|
+
void * const userdata)
|
189
|
+
{
|
190
|
+
xmpp_debug(conn->ctx, "xmpp", "didn't get stream features");
|
191
|
+
|
192
|
+
/* legacy auth will be attempted */
|
193
|
+
_auth(conn);
|
194
|
+
|
195
|
+
return 0;
|
196
|
+
}
|
197
|
+
|
198
|
+
|
199
|
+
|
200
|
+
static int _handle_features(xmpp_conn_t * const conn,
|
201
|
+
xmpp_stanza_t * const stanza,
|
202
|
+
void * const userdata)
|
203
|
+
{
|
204
|
+
xmpp_stanza_t *child, *mech;
|
205
|
+
char *text;
|
206
|
+
|
207
|
+
/* remove the handler that detects missing stream:features */
|
208
|
+
xmpp_timed_handler_delete(conn, _handle_missing_features);
|
209
|
+
|
210
|
+
/* check for TLS */
|
211
|
+
child = xmpp_stanza_get_child_by_name(stanza, "starttls");
|
212
|
+
if (child && (strcmp(xmpp_stanza_get_ns(child), XMPP_NS_TLS) == 0))
|
213
|
+
conn->tls_support = 1;
|
214
|
+
|
215
|
+
/* check for SASL */
|
216
|
+
child = xmpp_stanza_get_child_by_name(stanza, "mechanisms");
|
217
|
+
if (child && (strcmp(xmpp_stanza_get_ns(child), XMPP_NS_SASL) == 0)) {
|
218
|
+
for (mech = xmpp_stanza_get_children(child); mech;
|
219
|
+
mech = xmpp_stanza_get_next(mech)) {
|
220
|
+
if (strcmp(xmpp_stanza_get_name(mech), "mechanism") == 0) {
|
221
|
+
text = xmpp_stanza_get_text(mech);
|
222
|
+
if (strcasecmp(text, "PLAIN") == 0)
|
223
|
+
conn->sasl_support |= SASL_MASK_PLAIN;
|
224
|
+
else if (strcasecmp(text, "DIGEST-MD5") == 0)
|
225
|
+
conn->sasl_support |= SASL_MASK_DIGESTMD5;
|
226
|
+
else if (strcasecmp(text, "ANONYMOUS") == 0)
|
227
|
+
conn->sasl_support |= SASL_MASK_ANONYMOUS;
|
228
|
+
|
229
|
+
xmpp_free(conn->ctx, text);
|
230
|
+
}
|
231
|
+
}
|
232
|
+
}
|
233
|
+
|
234
|
+
if (conn->pass == NULL || conn->pass[0] == '\0') {
|
235
|
+
xmpp_debug(conn->ctx, "auth", "do not attempt auth as there is no password given");
|
236
|
+
//If no password, do not login, this will give 'register' a chance to run
|
237
|
+
conn->authenticated = 1;
|
238
|
+
/* call connection handler */
|
239
|
+
conn->conn_handler(conn, XMPP_CONN_CONNECT, 0, NULL, conn->userdata);
|
240
|
+
} else {
|
241
|
+
_auth(conn);
|
242
|
+
}
|
243
|
+
|
244
|
+
return 0;
|
245
|
+
}
|
246
|
+
|
247
|
+
/* returns the correct auth id for a component or a client.
|
248
|
+
* returned string must be freed by caller */
|
249
|
+
static char *_get_authid(xmpp_conn_t * const conn)
|
250
|
+
{
|
251
|
+
char *authid = NULL;
|
252
|
+
|
253
|
+
if (conn->type == XMPP_CLIENT) {
|
254
|
+
/* authid is the node portion of jid */
|
255
|
+
if (!conn->jid) return NULL;
|
256
|
+
authid = xmpp_jid_node(conn->ctx, conn->jid);
|
257
|
+
}
|
258
|
+
|
259
|
+
return authid;
|
260
|
+
}
|
261
|
+
|
262
|
+
static int _handle_proceedtls_default(xmpp_conn_t * const conn,
|
263
|
+
xmpp_stanza_t * const stanza,
|
264
|
+
void * const userdata)
|
265
|
+
{
|
266
|
+
char *name;
|
267
|
+
name = xmpp_stanza_get_name(stanza);
|
268
|
+
xmpp_debug(conn->ctx, "xmpp",
|
269
|
+
"handle proceedtls called for %s", name);
|
270
|
+
|
271
|
+
if (strcmp(name, "proceed") == 0) {
|
272
|
+
xmpp_debug(conn->ctx, "xmpp", "proceeding with TLS");
|
273
|
+
|
274
|
+
conn->tls = tls_new(conn->ctx, conn->sock);
|
275
|
+
|
276
|
+
if (!tls_start(conn->tls))
|
277
|
+
{
|
278
|
+
xmpp_debug(conn->ctx, "xmpp", "Couldn't start TLS! error %d", tls_error(conn->tls));
|
279
|
+
tls_free(conn->tls);
|
280
|
+
conn->tls = NULL;
|
281
|
+
conn->tls_failed = 1;
|
282
|
+
|
283
|
+
/* failed tls spoils the connection, so disconnect */
|
284
|
+
xmpp_disconnect(conn);
|
285
|
+
}
|
286
|
+
else
|
287
|
+
{
|
288
|
+
parser_prepare_reset(conn, _handle_open_tls);
|
289
|
+
|
290
|
+
conn_open_stream(conn);
|
291
|
+
}
|
292
|
+
}
|
293
|
+
|
294
|
+
return 0;
|
295
|
+
}
|
296
|
+
|
297
|
+
static int _handle_sasl_result(xmpp_conn_t * const conn,
|
298
|
+
xmpp_stanza_t * const stanza,
|
299
|
+
void * const userdata)
|
300
|
+
{
|
301
|
+
char *name;
|
302
|
+
|
303
|
+
name = xmpp_stanza_get_name(stanza);
|
304
|
+
|
305
|
+
/* the server should send a <success> or <failure> stanza */
|
306
|
+
if (strcmp(name, "failure") == 0) {
|
307
|
+
xmpp_debug(conn->ctx, "xmpp", "SASL %s auth failed",
|
308
|
+
(char *)userdata);
|
309
|
+
|
310
|
+
/* fall back to next auth method */
|
311
|
+
_auth(conn);
|
312
|
+
} else if (strcmp(name, "success") == 0) {
|
313
|
+
/* SASL PLAIN auth successful, we need to restart the stream */
|
314
|
+
xmpp_debug(conn->ctx, "xmpp", "SASL %s auth successful",
|
315
|
+
(char *)userdata);
|
316
|
+
|
317
|
+
/* reset parser */
|
318
|
+
parser_prepare_reset(conn, _handle_open_sasl);
|
319
|
+
|
320
|
+
/* send stream tag */
|
321
|
+
conn_open_stream(conn);
|
322
|
+
} else {
|
323
|
+
/* got unexpected reply */
|
324
|
+
xmpp_error(conn->ctx, "xmpp", "Got unexpected reply to SASL %s"\
|
325
|
+
"authentication.", (char *)userdata);
|
326
|
+
xmpp_disconnect(conn);
|
327
|
+
}
|
328
|
+
|
329
|
+
return 0;
|
330
|
+
}
|
331
|
+
|
332
|
+
/* handle the challenge phase of digest auth */
|
333
|
+
static int _handle_digestmd5_challenge(xmpp_conn_t * const conn,
|
334
|
+
xmpp_stanza_t * const stanza,
|
335
|
+
void * const userdata)
|
336
|
+
{
|
337
|
+
char *text;
|
338
|
+
char *response;
|
339
|
+
xmpp_stanza_t *auth, *authdata;
|
340
|
+
char *name;
|
341
|
+
|
342
|
+
name = xmpp_stanza_get_name(stanza);
|
343
|
+
xmpp_debug(conn->ctx, "xmpp",\
|
344
|
+
"handle digest-md5 (challenge) called for %s", name);
|
345
|
+
|
346
|
+
if (strcmp(name, "challenge") == 0) {
|
347
|
+
text = xmpp_stanza_get_text(stanza);
|
348
|
+
response = sasl_digest_md5(conn->ctx, text, conn->jid, conn->pass);
|
349
|
+
if (!response) {
|
350
|
+
disconnect_mem_error(conn);
|
351
|
+
return 0;
|
352
|
+
}
|
353
|
+
xmpp_free(conn->ctx, text);
|
354
|
+
|
355
|
+
auth = xmpp_stanza_new(conn->ctx);
|
356
|
+
if (!auth) {
|
357
|
+
disconnect_mem_error(conn);
|
358
|
+
return 0;
|
359
|
+
}
|
360
|
+
xmpp_stanza_set_name(auth, "response");
|
361
|
+
xmpp_stanza_set_ns(auth, XMPP_NS_SASL);
|
362
|
+
|
363
|
+
authdata = xmpp_stanza_new(conn->ctx);
|
364
|
+
if (!authdata) {
|
365
|
+
disconnect_mem_error(conn);
|
366
|
+
return 0;
|
367
|
+
}
|
368
|
+
|
369
|
+
xmpp_stanza_set_text(authdata, response);
|
370
|
+
xmpp_free(conn->ctx, response);
|
371
|
+
|
372
|
+
xmpp_stanza_add_child(auth, authdata);
|
373
|
+
xmpp_stanza_release(authdata);
|
374
|
+
|
375
|
+
handler_add(conn, _handle_digestmd5_rspauth,
|
376
|
+
XMPP_NS_SASL, NULL, NULL, NULL);
|
377
|
+
|
378
|
+
xmpp_send(conn, auth);
|
379
|
+
xmpp_stanza_release(auth);
|
380
|
+
|
381
|
+
} else {
|
382
|
+
return _handle_sasl_result(conn, stanza, "DIGEST-MD5");
|
383
|
+
}
|
384
|
+
|
385
|
+
/* remove ourselves */
|
386
|
+
return 0;
|
387
|
+
}
|
388
|
+
|
389
|
+
/* handle the rspauth phase of digest auth */
|
390
|
+
static int _handle_digestmd5_rspauth(xmpp_conn_t * const conn,
|
391
|
+
xmpp_stanza_t * const stanza,
|
392
|
+
void * const userdata)
|
393
|
+
{
|
394
|
+
xmpp_stanza_t *auth;
|
395
|
+
char *name;
|
396
|
+
|
397
|
+
name = xmpp_stanza_get_name(stanza);
|
398
|
+
xmpp_debug(conn->ctx, "xmpp",
|
399
|
+
"handle digest-md5 (rspauth) called for %s", name);
|
400
|
+
|
401
|
+
|
402
|
+
if (strcmp(name, "challenge") == 0) {
|
403
|
+
/* assume it's an rspauth response */
|
404
|
+
auth = xmpp_stanza_new(conn->ctx);
|
405
|
+
if (!auth) {
|
406
|
+
disconnect_mem_error(conn);
|
407
|
+
return 0;
|
408
|
+
}
|
409
|
+
xmpp_stanza_set_name(auth, "response");
|
410
|
+
xmpp_stanza_set_ns(auth, XMPP_NS_SASL);
|
411
|
+
xmpp_send(conn, auth);
|
412
|
+
xmpp_stanza_release(auth);
|
413
|
+
} else {
|
414
|
+
return _handle_sasl_result(conn, stanza, "DIGEST-MD5");
|
415
|
+
}
|
416
|
+
|
417
|
+
return 1;
|
418
|
+
}
|
419
|
+
|
420
|
+
static xmpp_stanza_t *_make_starttls(xmpp_conn_t * const conn)
|
421
|
+
{
|
422
|
+
xmpp_stanza_t *starttls;
|
423
|
+
|
424
|
+
/* build start stanza */
|
425
|
+
starttls = xmpp_stanza_new(conn->ctx);
|
426
|
+
if (starttls) {
|
427
|
+
xmpp_stanza_set_name(starttls, "starttls");
|
428
|
+
xmpp_stanza_set_ns(starttls, XMPP_NS_TLS);
|
429
|
+
}
|
430
|
+
|
431
|
+
return starttls;
|
432
|
+
}
|
433
|
+
|
434
|
+
static xmpp_stanza_t *_make_sasl_auth(xmpp_conn_t * const conn,
|
435
|
+
const char * const mechanism)
|
436
|
+
{
|
437
|
+
xmpp_stanza_t *auth;
|
438
|
+
|
439
|
+
/* build auth stanza */
|
440
|
+
auth = xmpp_stanza_new(conn->ctx);
|
441
|
+
if (auth) {
|
442
|
+
xmpp_stanza_set_name(auth, "auth");
|
443
|
+
xmpp_stanza_set_ns(auth, XMPP_NS_SASL);
|
444
|
+
xmpp_stanza_set_attribute(auth, "mechanism", mechanism);
|
445
|
+
}
|
446
|
+
|
447
|
+
return auth;
|
448
|
+
}
|
449
|
+
|
450
|
+
/* authenticate the connection
|
451
|
+
* this may get called multiple times. if any auth method fails,
|
452
|
+
* this will get called again until one auth method succeeds or every
|
453
|
+
* method fails
|
454
|
+
*/
|
455
|
+
static void _auth(xmpp_conn_t * const conn)
|
456
|
+
{
|
457
|
+
xmpp_stanza_t *auth, *authdata, *query, *child, *iq;
|
458
|
+
char *str, *authid;
|
459
|
+
int anonjid;
|
460
|
+
|
461
|
+
/* if there is no node in conn->jid, we assume anonymous connect */
|
462
|
+
str = xmpp_jid_node(conn->ctx, conn->jid);
|
463
|
+
if (str == NULL) {
|
464
|
+
anonjid = 1;
|
465
|
+
} else {
|
466
|
+
xmpp_free(conn->ctx, str);
|
467
|
+
anonjid = 0;
|
468
|
+
}
|
469
|
+
|
470
|
+
if (conn->tls_support)
|
471
|
+
{
|
472
|
+
tls_t *tls = tls_new(conn->ctx, conn->sock);
|
473
|
+
|
474
|
+
/* If we couldn't init tls, it isn't there, so go on */
|
475
|
+
if (!tls)
|
476
|
+
{
|
477
|
+
conn->tls_support = 0;
|
478
|
+
_auth(conn);
|
479
|
+
return;
|
480
|
+
}
|
481
|
+
else
|
482
|
+
{
|
483
|
+
tls_free(tls);
|
484
|
+
}
|
485
|
+
|
486
|
+
auth = _make_starttls(conn);
|
487
|
+
|
488
|
+
if (!auth) {
|
489
|
+
disconnect_mem_error(conn);
|
490
|
+
return;
|
491
|
+
}
|
492
|
+
|
493
|
+
handler_add(conn, _handle_proceedtls_default,
|
494
|
+
XMPP_NS_TLS, NULL, NULL, NULL);
|
495
|
+
|
496
|
+
xmpp_send(conn, auth);
|
497
|
+
xmpp_stanza_release(auth);
|
498
|
+
|
499
|
+
/* TLS was tried, unset flag */
|
500
|
+
conn->tls_support = 0;
|
501
|
+
} else if (anonjid && conn->sasl_support & SASL_MASK_ANONYMOUS) {
|
502
|
+
/* some crap here */
|
503
|
+
auth = _make_sasl_auth(conn, "ANONYMOUS");
|
504
|
+
if (!auth) {
|
505
|
+
disconnect_mem_error(conn);
|
506
|
+
return;
|
507
|
+
}
|
508
|
+
|
509
|
+
handler_add(conn, _handle_sasl_result, XMPP_NS_SASL,
|
510
|
+
NULL, NULL, "ANONYMOUS");
|
511
|
+
|
512
|
+
xmpp_send(conn, auth);
|
513
|
+
xmpp_stanza_release(auth);
|
514
|
+
|
515
|
+
/* SASL ANONYMOUS was tried, unset flag */
|
516
|
+
conn->sasl_support &= ~SASL_MASK_ANONYMOUS;
|
517
|
+
} else if (anonjid) {
|
518
|
+
xmpp_error(conn->ctx, "auth",
|
519
|
+
"No node in JID, and SASL ANONYMOUS unsupported.");
|
520
|
+
xmpp_disconnect(conn);
|
521
|
+
} else if (conn->sasl_support & SASL_MASK_DIGESTMD5) {
|
522
|
+
auth = _make_sasl_auth(conn, "DIGEST-MD5");
|
523
|
+
if (!auth) {
|
524
|
+
disconnect_mem_error(conn);
|
525
|
+
return;
|
526
|
+
|
527
|
+
}
|
528
|
+
|
529
|
+
handler_add(conn, _handle_digestmd5_challenge,
|
530
|
+
XMPP_NS_SASL, NULL, NULL, NULL);
|
531
|
+
|
532
|
+
xmpp_send(conn, auth);
|
533
|
+
xmpp_stanza_release(auth);
|
534
|
+
|
535
|
+
/* SASL DIGEST-MD5 was tried, unset flag */
|
536
|
+
conn->sasl_support &= ~SASL_MASK_DIGESTMD5;
|
537
|
+
} else if (conn->sasl_support & SASL_MASK_PLAIN) {
|
538
|
+
auth = _make_sasl_auth(conn, "PLAIN");
|
539
|
+
if (!auth) {
|
540
|
+
disconnect_mem_error(conn);
|
541
|
+
return;
|
542
|
+
}
|
543
|
+
authdata = xmpp_stanza_new(conn->ctx);
|
544
|
+
if (!authdata) {
|
545
|
+
disconnect_mem_error(conn);
|
546
|
+
return;
|
547
|
+
}
|
548
|
+
authid = _get_authid(conn);
|
549
|
+
if (!authid) {
|
550
|
+
disconnect_mem_error(conn);
|
551
|
+
return;
|
552
|
+
}
|
553
|
+
str = sasl_plain(conn->ctx, authid, conn->pass);
|
554
|
+
if (!str) {
|
555
|
+
disconnect_mem_error(conn);
|
556
|
+
return;
|
557
|
+
}
|
558
|
+
xmpp_stanza_set_text(authdata, str);
|
559
|
+
xmpp_free(conn->ctx, str);
|
560
|
+
|
561
|
+
xmpp_stanza_add_child(auth, authdata);
|
562
|
+
xmpp_stanza_release(authdata);
|
563
|
+
|
564
|
+
handler_add(conn, _handle_sasl_result,
|
565
|
+
XMPP_NS_SASL, NULL, NULL, "PLAIN");
|
566
|
+
|
567
|
+
xmpp_send(conn, auth);
|
568
|
+
xmpp_stanza_release(auth);
|
569
|
+
|
570
|
+
/* SASL PLAIN was tried */
|
571
|
+
conn->sasl_support &= ~SASL_MASK_PLAIN;
|
572
|
+
} else if (conn->type == XMPP_CLIENT) {
|
573
|
+
/* legacy client authentication */
|
574
|
+
|
575
|
+
iq = xmpp_stanza_new(conn->ctx);
|
576
|
+
if (!iq) {
|
577
|
+
disconnect_mem_error(conn);
|
578
|
+
return;
|
579
|
+
}
|
580
|
+
xmpp_stanza_set_name(iq, "iq");
|
581
|
+
xmpp_stanza_set_type(iq, "set");
|
582
|
+
xmpp_stanza_set_id(iq, "_xmpp_auth1");
|
583
|
+
|
584
|
+
query = xmpp_stanza_new(conn->ctx);
|
585
|
+
if (!query) {
|
586
|
+
xmpp_stanza_release(iq);
|
587
|
+
disconnect_mem_error(conn);
|
588
|
+
return;
|
589
|
+
}
|
590
|
+
xmpp_stanza_set_name(query, "query");
|
591
|
+
xmpp_stanza_set_ns(query, XMPP_NS_AUTH);
|
592
|
+
xmpp_stanza_add_child(iq, query);
|
593
|
+
xmpp_stanza_release(query);
|
594
|
+
|
595
|
+
child = xmpp_stanza_new(conn->ctx);
|
596
|
+
if (!child) {
|
597
|
+
xmpp_stanza_release(iq);
|
598
|
+
disconnect_mem_error(conn);
|
599
|
+
return;
|
600
|
+
}
|
601
|
+
xmpp_stanza_set_name(child, "username");
|
602
|
+
xmpp_stanza_add_child(query, child);
|
603
|
+
xmpp_stanza_release(child);
|
604
|
+
|
605
|
+
authdata = xmpp_stanza_new(conn->ctx);
|
606
|
+
if (!authdata) {
|
607
|
+
xmpp_stanza_release(iq);
|
608
|
+
disconnect_mem_error(conn);
|
609
|
+
return;
|
610
|
+
}
|
611
|
+
str = xmpp_jid_node(conn->ctx, conn->jid);
|
612
|
+
xmpp_stanza_set_text(authdata, str);
|
613
|
+
xmpp_free(conn->ctx, str);
|
614
|
+
xmpp_stanza_add_child(child, authdata);
|
615
|
+
xmpp_stanza_release(authdata);
|
616
|
+
|
617
|
+
child = xmpp_stanza_new(conn->ctx);
|
618
|
+
if (!child) {
|
619
|
+
xmpp_stanza_release(iq);
|
620
|
+
disconnect_mem_error(conn);
|
621
|
+
return;
|
622
|
+
}
|
623
|
+
xmpp_stanza_set_name(child, "password");
|
624
|
+
xmpp_stanza_add_child(query, child);
|
625
|
+
xmpp_stanza_release(child);
|
626
|
+
|
627
|
+
authdata = xmpp_stanza_new(conn->ctx);
|
628
|
+
if (!authdata) {
|
629
|
+
xmpp_stanza_release(iq);
|
630
|
+
disconnect_mem_error(conn);
|
631
|
+
return;
|
632
|
+
}
|
633
|
+
xmpp_stanza_set_text(authdata, conn->pass);
|
634
|
+
xmpp_stanza_add_child(child, authdata);
|
635
|
+
xmpp_stanza_release(authdata);
|
636
|
+
|
637
|
+
child = xmpp_stanza_new(conn->ctx);
|
638
|
+
if (!child) {
|
639
|
+
xmpp_stanza_release(iq);
|
640
|
+
disconnect_mem_error(conn);
|
641
|
+
return;
|
642
|
+
}
|
643
|
+
xmpp_stanza_set_name(child, "resource");
|
644
|
+
xmpp_stanza_add_child(query, child);
|
645
|
+
xmpp_stanza_release(child);
|
646
|
+
|
647
|
+
authdata = xmpp_stanza_new(conn->ctx);
|
648
|
+
if (!authdata) {
|
649
|
+
xmpp_stanza_release(iq);
|
650
|
+
disconnect_mem_error(conn);
|
651
|
+
return;
|
652
|
+
}
|
653
|
+
str = xmpp_jid_resource(conn->ctx, conn->jid);
|
654
|
+
if (str) {
|
655
|
+
xmpp_stanza_set_text(authdata, str);
|
656
|
+
xmpp_free(conn->ctx, str);
|
657
|
+
} else {
|
658
|
+
xmpp_stanza_release(authdata);
|
659
|
+
xmpp_stanza_release(iq);
|
660
|
+
xmpp_error(conn->ctx, "auth",
|
661
|
+
"Cannot authenticate without resource");
|
662
|
+
xmpp_disconnect(conn);
|
663
|
+
return;
|
664
|
+
}
|
665
|
+
xmpp_stanza_add_child(child, authdata);
|
666
|
+
xmpp_stanza_release(authdata);
|
667
|
+
|
668
|
+
handler_add_id(conn, _handle_legacy, "_xmpp_auth1", NULL);
|
669
|
+
handler_add_timed(conn, _handle_missing_legacy,
|
670
|
+
LEGACY_TIMEOUT, NULL);
|
671
|
+
|
672
|
+
xmpp_send(conn, iq);
|
673
|
+
xmpp_stanza_release(iq);
|
674
|
+
}
|
675
|
+
}
|
676
|
+
|
677
|
+
|
678
|
+
/** Set up handlers at stream start.
|
679
|
+
* This function is called internally to Strophe for handling the opening
|
680
|
+
* of an XMPP stream. It's called by the parser when a stream is opened
|
681
|
+
* or reset, and adds the initial handlers for <stream:error/> and
|
682
|
+
* <stream:features/>. This function is not intended for use outside
|
683
|
+
* of Strophe.
|
684
|
+
*
|
685
|
+
* @param conn a Strophe connection object
|
686
|
+
*/
|
687
|
+
void auth_handle_open(xmpp_conn_t * const conn)
|
688
|
+
{
|
689
|
+
/* reset all timed handlers */
|
690
|
+
handler_reset_timed(conn, 0);
|
691
|
+
|
692
|
+
/* setup handler for stream:error */
|
693
|
+
handler_add(conn, _handle_error,
|
694
|
+
NULL, "stream:error", NULL, NULL);
|
695
|
+
|
696
|
+
/* setup handlers for incoming <stream:features> */
|
697
|
+
handler_add(conn, _handle_features,
|
698
|
+
NULL, "stream:features", NULL, NULL);
|
699
|
+
handler_add_timed(conn, _handle_missing_features,
|
700
|
+
FEATURES_TIMEOUT, NULL);
|
701
|
+
}
|
702
|
+
|
703
|
+
/* called when stream:stream tag received after TLS connection */
|
704
|
+
static void _handle_open_tls(xmpp_conn_t * const conn)
|
705
|
+
{
|
706
|
+
xmpp_debug(conn->ctx, "xmpp", "TLS successful, proceeding with SASL");
|
707
|
+
|
708
|
+
/* go straight to SASL auth */
|
709
|
+
_auth(conn);
|
710
|
+
}
|
711
|
+
|
712
|
+
|
713
|
+
/* called when stream:stream tag received after SASL auth */
|
714
|
+
static void _handle_open_sasl(xmpp_conn_t * const conn)
|
715
|
+
{
|
716
|
+
xmpp_debug(conn->ctx, "xmpp", "Reopened stream successfully.");
|
717
|
+
|
718
|
+
/* setup stream:features handlers */
|
719
|
+
handler_add(conn, _handle_features_sasl,
|
720
|
+
NULL, "stream:features", NULL, NULL);
|
721
|
+
handler_add_timed(conn, _handle_missing_features_sasl,
|
722
|
+
FEATURES_TIMEOUT, NULL);
|
723
|
+
}
|
724
|
+
|
725
|
+
static int _handle_features_sasl(xmpp_conn_t * const conn,
|
726
|
+
xmpp_stanza_t * const stanza,
|
727
|
+
void * const userdata)
|
728
|
+
{
|
729
|
+
xmpp_stanza_t *bind, *session, *iq, *res, *text;
|
730
|
+
char *resource;
|
731
|
+
|
732
|
+
/* remove missing features handler */
|
733
|
+
xmpp_timed_handler_delete(conn, _handle_missing_features_sasl);
|
734
|
+
|
735
|
+
/* we are expecting <bind/> and <session/> since this is a
|
736
|
+
XMPP style connection */
|
737
|
+
|
738
|
+
bind = xmpp_stanza_get_child_by_name(stanza, "bind");
|
739
|
+
if (bind && strcmp(xmpp_stanza_get_ns(bind), XMPP_NS_BIND) == 0) {
|
740
|
+
/* resource binding is required */
|
741
|
+
conn->bind_required = 1;
|
742
|
+
}
|
743
|
+
|
744
|
+
session = xmpp_stanza_get_child_by_name(stanza, "session");
|
745
|
+
if (session && strcmp(xmpp_stanza_get_ns(session), XMPP_NS_SESSION) == 0) {
|
746
|
+
/* session establishment required */
|
747
|
+
conn->session_required = 1;
|
748
|
+
}
|
749
|
+
|
750
|
+
/* if bind is required, go ahead and start it */
|
751
|
+
if (conn->bind_required) {
|
752
|
+
/* bind resource */
|
753
|
+
|
754
|
+
/* setup response handlers */
|
755
|
+
handler_add_id(conn, _handle_bind, "_xmpp_bind1", NULL);
|
756
|
+
handler_add_timed(conn, _handle_missing_bind,
|
757
|
+
BIND_TIMEOUT, NULL);
|
758
|
+
|
759
|
+
/* send bind request */
|
760
|
+
iq = xmpp_stanza_new(conn->ctx);
|
761
|
+
if (!iq) {
|
762
|
+
disconnect_mem_error(conn);
|
763
|
+
return 0;
|
764
|
+
}
|
765
|
+
|
766
|
+
xmpp_stanza_set_name(iq, "iq");
|
767
|
+
xmpp_stanza_set_type(iq, "set");
|
768
|
+
xmpp_stanza_set_id(iq, "_xmpp_bind1");
|
769
|
+
|
770
|
+
bind = xmpp_stanza_copy(bind);
|
771
|
+
if (!bind) {
|
772
|
+
xmpp_stanza_release(iq);
|
773
|
+
disconnect_mem_error(conn);
|
774
|
+
return 0;
|
775
|
+
}
|
776
|
+
|
777
|
+
/* request a specific resource if we have one */
|
778
|
+
resource = xmpp_jid_resource(conn->ctx, conn->jid);
|
779
|
+
if ((resource != NULL) && (strlen(resource) == 0)) {
|
780
|
+
/* jabberd2 doesn't handle an empty resource */
|
781
|
+
xmpp_free(conn->ctx, resource);
|
782
|
+
resource = NULL;
|
783
|
+
}
|
784
|
+
|
785
|
+
/* if we have a resource to request, do it. otherwise the
|
786
|
+
server will assign us one */
|
787
|
+
if (resource) {
|
788
|
+
res = xmpp_stanza_new(conn->ctx);
|
789
|
+
if (!res) {
|
790
|
+
xmpp_stanza_release(bind);
|
791
|
+
xmpp_stanza_release(iq);
|
792
|
+
disconnect_mem_error(conn);
|
793
|
+
return 0;
|
794
|
+
}
|
795
|
+
xmpp_stanza_set_name(res, "resource");
|
796
|
+
text = xmpp_stanza_new(conn->ctx);
|
797
|
+
if (!text) {
|
798
|
+
xmpp_stanza_release(res);
|
799
|
+
xmpp_stanza_release(bind);
|
800
|
+
xmpp_stanza_release(iq);
|
801
|
+
disconnect_mem_error(conn);
|
802
|
+
return 0;
|
803
|
+
}
|
804
|
+
xmpp_stanza_set_text(text, resource);
|
805
|
+
xmpp_stanza_add_child(res, text);
|
806
|
+
xmpp_stanza_add_child(bind, res);
|
807
|
+
xmpp_free(conn->ctx, resource);
|
808
|
+
}
|
809
|
+
|
810
|
+
xmpp_stanza_add_child(iq, bind);
|
811
|
+
xmpp_stanza_release(bind);
|
812
|
+
|
813
|
+
/* send bind request */
|
814
|
+
xmpp_send(conn, iq);
|
815
|
+
xmpp_stanza_release(iq);
|
816
|
+
} else {
|
817
|
+
/* can't bind, disconnect */
|
818
|
+
xmpp_error(conn->ctx, "xmpp", "Stream features does not allow "\
|
819
|
+
"resource bind.");
|
820
|
+
xmpp_disconnect(conn);
|
821
|
+
}
|
822
|
+
|
823
|
+
return 0;
|
824
|
+
}
|
825
|
+
|
826
|
+
static int _handle_missing_features_sasl(xmpp_conn_t * const conn,
|
827
|
+
void * const userdata)
|
828
|
+
{
|
829
|
+
xmpp_error(conn->ctx, "xmpp", "Did not receive stream features "\
|
830
|
+
"after SASL authentication.");
|
831
|
+
xmpp_disconnect(conn);
|
832
|
+
return 0;
|
833
|
+
}
|
834
|
+
|
835
|
+
static int _handle_bind(xmpp_conn_t * const conn,
|
836
|
+
xmpp_stanza_t * const stanza,
|
837
|
+
void * const userdata)
|
838
|
+
{
|
839
|
+
char *type;
|
840
|
+
xmpp_stanza_t *iq, *session;
|
841
|
+
|
842
|
+
/* delete missing bind handler */
|
843
|
+
xmpp_timed_handler_delete(conn, _handle_missing_bind);
|
844
|
+
|
845
|
+
/* server has replied to bind request */
|
846
|
+
type = xmpp_stanza_get_type(stanza);
|
847
|
+
if (type && strcmp(type, "error") == 0) {
|
848
|
+
xmpp_error(conn->ctx, "xmpp", "Binding failed.");
|
849
|
+
xmpp_disconnect(conn);
|
850
|
+
} else if (type && strcmp(type, "result") == 0) {
|
851
|
+
/* TODO: extract resource if present */
|
852
|
+
xmpp_debug(conn->ctx, "xmpp", "Bind successful.");
|
853
|
+
|
854
|
+
/* establish a session if required */
|
855
|
+
if (conn->session_required) {
|
856
|
+
/* setup response handlers */
|
857
|
+
handler_add_id(conn, _handle_session, "_xmpp_session1", NULL);
|
858
|
+
handler_add_timed(conn, _handle_missing_session,
|
859
|
+
SESSION_TIMEOUT, NULL);
|
860
|
+
|
861
|
+
/* send session request */
|
862
|
+
iq = xmpp_stanza_new(conn->ctx);
|
863
|
+
if (!iq) {
|
864
|
+
disconnect_mem_error(conn);
|
865
|
+
return 0;
|
866
|
+
}
|
867
|
+
|
868
|
+
xmpp_stanza_set_name(iq, "iq");
|
869
|
+
xmpp_stanza_set_type(iq, "set");
|
870
|
+
xmpp_stanza_set_id(iq, "_xmpp_session1");
|
871
|
+
|
872
|
+
session = xmpp_stanza_new(conn->ctx);
|
873
|
+
if (!session) {
|
874
|
+
xmpp_stanza_release(iq);
|
875
|
+
disconnect_mem_error(conn);
|
876
|
+
}
|
877
|
+
|
878
|
+
xmpp_stanza_set_name(session, "session");
|
879
|
+
xmpp_stanza_set_ns(session, XMPP_NS_SESSION);
|
880
|
+
|
881
|
+
xmpp_stanza_add_child(iq, session);
|
882
|
+
xmpp_stanza_release(session);
|
883
|
+
|
884
|
+
/* send session establishment request */
|
885
|
+
xmpp_send(conn, iq);
|
886
|
+
xmpp_stanza_release(iq);
|
887
|
+
} else {
|
888
|
+
conn->authenticated = 1;
|
889
|
+
|
890
|
+
/* call connection handler */
|
891
|
+
conn->conn_handler(conn, XMPP_CONN_CONNECT, 0, NULL,
|
892
|
+
conn->userdata);
|
893
|
+
}
|
894
|
+
} else {
|
895
|
+
xmpp_error(conn->ctx, "xmpp", "Server sent malformed bind reply.");
|
896
|
+
xmpp_disconnect(conn);
|
897
|
+
}
|
898
|
+
|
899
|
+
return 0;
|
900
|
+
}
|
901
|
+
|
902
|
+
static int _handle_missing_bind(xmpp_conn_t * const conn,
|
903
|
+
void * const userdata)
|
904
|
+
{
|
905
|
+
xmpp_error(conn->ctx, "xmpp", "Server did not reply to bind request.");
|
906
|
+
xmpp_disconnect(conn);
|
907
|
+
return 0;
|
908
|
+
}
|
909
|
+
|
910
|
+
static int _handle_session(xmpp_conn_t * const conn,
|
911
|
+
xmpp_stanza_t * const stanza,
|
912
|
+
void * const userdata)
|
913
|
+
{
|
914
|
+
char *type;
|
915
|
+
|
916
|
+
/* delete missing session handler */
|
917
|
+
xmpp_timed_handler_delete(conn, _handle_missing_session);
|
918
|
+
|
919
|
+
/* server has replied to the session request */
|
920
|
+
type = xmpp_stanza_get_type(stanza);
|
921
|
+
if (type && strcmp(type, "error") == 0) {
|
922
|
+
xmpp_error(conn->ctx, "xmpp", "Session establishment failed.");
|
923
|
+
xmpp_disconnect(conn);
|
924
|
+
} else if (type && strcmp(type, "result") == 0) {
|
925
|
+
xmpp_debug(conn->ctx, "xmpp", "Session establishment successful.");
|
926
|
+
|
927
|
+
conn->authenticated = 1;
|
928
|
+
|
929
|
+
/* call connection handler */
|
930
|
+
conn->conn_handler(conn, XMPP_CONN_CONNECT, 0, NULL, conn->userdata);
|
931
|
+
} else {
|
932
|
+
xmpp_error(conn->ctx, "xmpp", "Server sent malformed session reply.");
|
933
|
+
xmpp_disconnect(conn);
|
934
|
+
}
|
935
|
+
|
936
|
+
return 0;
|
937
|
+
}
|
938
|
+
|
939
|
+
static int _handle_missing_session(xmpp_conn_t * const conn,
|
940
|
+
void * const userdata)
|
941
|
+
{
|
942
|
+
xmpp_error(conn->ctx, "xmpp", "Server did not reply to session request.");
|
943
|
+
xmpp_disconnect(conn);
|
944
|
+
return 0;
|
945
|
+
}
|
946
|
+
|
947
|
+
static int _handle_legacy(xmpp_conn_t * const conn,
|
948
|
+
xmpp_stanza_t * const stanza,
|
949
|
+
void * const userdata)
|
950
|
+
{
|
951
|
+
char *type, *name;
|
952
|
+
|
953
|
+
/* delete missing handler */
|
954
|
+
xmpp_timed_handler_delete(conn, _handle_missing_legacy);
|
955
|
+
|
956
|
+
/* server responded to legacy auth request */
|
957
|
+
type = xmpp_stanza_get_type(stanza);
|
958
|
+
name = xmpp_stanza_get_name(stanza);
|
959
|
+
if (!type || strcmp(name, "iq") != 0) {
|
960
|
+
xmpp_error(conn->ctx, "xmpp", "Server sent us an unexpected response "\
|
961
|
+
"to legacy authentication request.");
|
962
|
+
xmpp_disconnect(conn);
|
963
|
+
} else if (strcmp(type, "error") == 0) {
|
964
|
+
/* legacy client auth failed, no more fallbacks */
|
965
|
+
xmpp_error(conn->ctx, "xmpp", "Legacy client authentication failed.");
|
966
|
+
xmpp_disconnect(conn);
|
967
|
+
} else if (strcmp(type, "result") == 0) {
|
968
|
+
/* auth succeeded */
|
969
|
+
xmpp_debug(conn->ctx, "xmpp", "Legacy auth succeeded.");
|
970
|
+
|
971
|
+
conn->authenticated = 1;
|
972
|
+
conn->conn_handler(conn, XMPP_CONN_CONNECT, 0, NULL, conn->userdata);
|
973
|
+
} else {
|
974
|
+
xmpp_error(conn->ctx, "xmpp", "Server sent us a legacy authentication "\
|
975
|
+
"response with a bad type.");
|
976
|
+
xmpp_disconnect(conn);
|
977
|
+
}
|
978
|
+
|
979
|
+
return 0;
|
980
|
+
}
|
981
|
+
|
982
|
+
static int _handle_missing_legacy(xmpp_conn_t * const conn,
|
983
|
+
void * const userdata)
|
984
|
+
{
|
985
|
+
xmpp_error(conn->ctx, "xmpp", "Server did not reply to legacy "\
|
986
|
+
"authentication request.");
|
987
|
+
xmpp_disconnect(conn);
|
988
|
+
return 0;
|
989
|
+
}
|
990
|
+
|