yong-stropheruby 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
|