stropheruby 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
data/ext/sasl.c ADDED
@@ -0,0 +1,614 @@
1
+ /* sasl.c
2
+ ** strophe XMPP client library -- SASL authentication helpers
3
+ **
4
+ ** Copyright (C) 2005-2008 OGG, LLC. All rights reserved.
5
+ **
6
+ ** This software is provided AS-IS with no warranty, either express
7
+ ** or 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
+ * SASL authentication.
17
+ */
18
+
19
+ #include <string.h>
20
+
21
+ #include "strophe.h"
22
+ #include "common.h"
23
+ #include "sasl.h"
24
+ #include "md5.h"
25
+
26
+ /* make sure the stdint.h types are available */
27
+ #if defined(_MSC_VER) /* Microsoft Visual C++ */
28
+ typedef signed char int8_t;
29
+ typedef short int int16_t;
30
+ typedef int int32_t;
31
+ typedef __int64 int64_t;
32
+
33
+ typedef unsigned char uint8_t;
34
+ typedef unsigned short int uint16_t;
35
+ typedef unsigned int uint32_t;
36
+ /* no uint64_t */
37
+ #else
38
+ #include <stdint.h>
39
+ #endif
40
+
41
+
42
+ /** generate authentication string for the SASL PLAIN mechanism */
43
+ char *sasl_plain(xmpp_ctx_t *ctx, const char *authid, const char *password) {
44
+ int idlen, passlen;
45
+ char *result = NULL;
46
+ char *msg;
47
+
48
+ /* our message is Base64(authzid,\0,authid,\0,password)
49
+ if there is no authzid, that field is left empty */
50
+
51
+ idlen = strlen(authid);
52
+ passlen = strlen(password);
53
+ msg = xmpp_alloc(ctx, 2 + idlen + passlen);
54
+ if (msg != NULL) {
55
+ msg[0] = '\0';
56
+ memcpy(msg+1, authid, idlen);
57
+ msg[1+idlen] = '\0';
58
+ memcpy(msg+1+idlen+1, password, passlen);
59
+ result = base64_encode(ctx, (unsigned char *)msg, 2 + idlen + passlen);
60
+ xmpp_free(ctx, msg);
61
+ }
62
+
63
+ return result;
64
+ }
65
+
66
+ /** helpers for digest auth */
67
+
68
+ /* create a new, null-terminated string from a substring */
69
+ static char *_make_string(xmpp_ctx_t *ctx, const char *s, const unsigned len)
70
+ {
71
+ char *result;
72
+
73
+ result = xmpp_alloc(ctx, len + 1);
74
+ if (result != NULL) {
75
+ memcpy(result, s, len);
76
+ result[len] = '\0';
77
+ }
78
+ return result;
79
+ }
80
+
81
+ /* create a new, null-terminated string quoting another string */
82
+ static char *_make_quoted(xmpp_ctx_t *ctx, const char *s)
83
+ {
84
+ char *result;
85
+ int len = strlen(s);
86
+
87
+ result = xmpp_alloc(ctx, len + 3);
88
+ if (result != NULL) {
89
+ result[0] = '"';
90
+ memcpy(result+1, s, len);
91
+ result[len+1] = '"';
92
+ result[len+2] = '\0';
93
+ }
94
+ return result;
95
+ }
96
+
97
+ /* split key, value pairs into a hash */
98
+ static hash_t *_parse_digest_challenge(xmpp_ctx_t *ctx, const char *msg)
99
+ {
100
+ hash_t *result;
101
+ unsigned char *text;
102
+ char *key, *value;
103
+ unsigned char *s, *t;
104
+
105
+ text = base64_decode(ctx, msg, strlen(msg));
106
+ if (text == NULL) {
107
+ xmpp_error(ctx, "SASL", "couldn't Base64 decode challenge!");
108
+ return NULL;
109
+ }
110
+
111
+ result = hash_new(ctx, 10, xmpp_free);
112
+ if (result != NULL) {
113
+ s = text;
114
+ while (*s != '\0') {
115
+ /* skip any leading commas and spaces */
116
+ while ((*s == ',') || (*s == ' ')) s++;
117
+ /* accumulate a key ending at '=' */
118
+ t = s;
119
+ while ((*t != '=') && (*t != '\0')) t++;
120
+ if (*t == '\0') break; /* bad string */
121
+ key = _make_string(ctx, (char *)s, (t-s));
122
+ if (key == NULL) break;
123
+ /* advance our start pointer past the key */
124
+ s = t + 1;
125
+ t = s;
126
+ /* if we see quotes, grab the string in between */
127
+ if ((*s == '\'') || (*s == '"')) {
128
+ t++;
129
+ while ((*t != *s) && (*t != '\0'))
130
+ t++;
131
+ value = _make_string(ctx, (char *)s+1, (t-s-1));
132
+ if (*t == *s) {
133
+ s = t + 1;
134
+ } else {
135
+ s = t;
136
+ }
137
+ /* otherwise, accumulate a value ending in ',' or '\0' */
138
+ } else {
139
+ while ((*t != ',') && (*t != '\0')) t++;
140
+ value = _make_string(ctx, (char *)s, (t-s));
141
+ s = t;
142
+ }
143
+ if (value == NULL) {
144
+ xmpp_free(ctx, key);
145
+ break;
146
+ }
147
+ /* TODO: check for collisions per spec */
148
+ hash_add(result, key, value);
149
+ /* hash table now owns the value, free the key */
150
+ xmpp_free(ctx, key);
151
+ }
152
+ }
153
+ xmpp_free(ctx, text);
154
+
155
+ return result;
156
+ }
157
+
158
+ /** expand a 16 byte MD5 digest to a 32 byte hex representation */
159
+ static void _digest_to_hex(const char *digest, char *hex)
160
+ {
161
+ int i;
162
+ const char hexdigit[] = "0123456789abcdef";
163
+
164
+ for (i = 0; i < 16; i++) {
165
+ *hex++ = hexdigit[ (digest[i] >> 4) & 0x0F ];
166
+ *hex++ = hexdigit[ digest[i] & 0x0F ];
167
+ }
168
+ }
169
+
170
+ /** append 'key="value"' to a buffer, growing as necessary */
171
+ static char *_add_key(xmpp_ctx_t *ctx, hash_t *table, const char *key,
172
+ char *buf, int *len, int quote)
173
+ {
174
+ int olen,nlen;
175
+ int keylen, valuelen;
176
+ const char *value, *qvalue;
177
+ char *c;
178
+
179
+ /* allocate a zero-length string if necessary */
180
+ if (buf == NULL) {
181
+ buf = xmpp_alloc(ctx, 1);
182
+ buf[0] = '\0';
183
+ }
184
+ if (buf == NULL) return NULL;
185
+
186
+ /* get current string length */
187
+ olen = strlen(buf);
188
+ value = hash_get(table, key);
189
+ if (value == NULL) {
190
+ xmpp_error(ctx, "SASL", "couldn't retrieve value for '%s'", key);
191
+ value = "";
192
+ }
193
+ if (quote) {
194
+ qvalue = _make_quoted(ctx, value);
195
+ } else {
196
+ qvalue = value;
197
+ }
198
+ /* added length is key + '=' + value */
199
+ /* (+ ',' if we're not the first entry */
200
+ keylen = strlen(key);
201
+ valuelen = strlen(qvalue);
202
+ nlen = (olen ? 1 : 0) + keylen + 1 + valuelen + 1;
203
+ buf = xmpp_realloc(ctx, buf, olen+nlen);
204
+
205
+ if (buf != NULL) {
206
+ c = buf + olen;
207
+ if (olen) *c++ = ',';
208
+ memcpy(c, key, keylen); c += keylen;
209
+ *c++ = '=';
210
+ memcpy(c, qvalue, valuelen); c += valuelen;
211
+ *c++ = '\0';
212
+ }
213
+
214
+ if (quote) xmpp_free(ctx, (char *)qvalue);
215
+
216
+ return buf;
217
+ }
218
+
219
+ /** generate auth response string for the SASL DIGEST-MD5 mechanism */
220
+ char *sasl_digest_md5(xmpp_ctx_t *ctx, const char *challenge,
221
+ const char *jid, const char *password) {
222
+ hash_t *table;
223
+ char *result = NULL;
224
+ char *node, *domain, *realm;
225
+ char *value;
226
+ char *response;
227
+ int rlen;
228
+ struct MD5Context MD5;
229
+ unsigned char digest[16], HA1[16], HA2[16];
230
+ char hex[32];
231
+
232
+ /* our digest response is
233
+ Hex( KD( HEX(MD5(A1)),
234
+ nonce ':' nc ':' cnonce ':' qop ':' HEX(MD5(A2))
235
+ ))
236
+
237
+ where KD(k, s) = MD5(k ':' s),
238
+ A1 = MD5( node ':' realm ':' password ) ':' nonce ':' cnonce
239
+ A2 = "AUTHENTICATE" ':' "xmpp/" domain
240
+
241
+ If there is an authzid it is ':'-appended to A1 */
242
+
243
+ /* parse the challenge */
244
+ table = _parse_digest_challenge(ctx, challenge);
245
+ if (table == NULL) {
246
+ xmpp_error(ctx, "SASL", "couldn't parse digest challenge");
247
+ return NULL;
248
+ }
249
+
250
+ node = xmpp_jid_node(ctx, jid);
251
+ domain = xmpp_jid_domain(ctx, jid);
252
+
253
+ /* generate default realm of domain if one didn't come from the
254
+ server */
255
+ realm = hash_get(table, "realm");
256
+ if (realm == NULL || strlen(realm) == 0) {
257
+ hash_add(table, "realm", xmpp_strdup(ctx, domain));
258
+ realm = hash_get(table, "realm");
259
+ }
260
+
261
+ /* add our response fields */
262
+ hash_add(table, "username", xmpp_strdup(ctx, node));
263
+ /* TODO: generate a random cnonce */
264
+ hash_add(table, "cnonce", xmpp_strdup(ctx, "00DEADBEEF00"));
265
+ hash_add(table, "nc", xmpp_strdup(ctx, "00000001"));
266
+ hash_add(table, "qop", xmpp_strdup(ctx, "auth"));
267
+ value = xmpp_alloc(ctx, 5 + strlen(domain) + 1);
268
+ memcpy(value, "xmpp/", 5);
269
+ memcpy(value+5, domain, strlen(domain));
270
+ value[5+strlen(domain)] = '\0';
271
+ hash_add(table, "digest-uri", value);
272
+
273
+ /* generate response */
274
+
275
+ /* construct MD5(node : realm : password) */
276
+ MD5Init(&MD5);
277
+ MD5Update(&MD5, (unsigned char *)node, strlen(node));
278
+ MD5Update(&MD5, (unsigned char *)":", 1);
279
+ MD5Update(&MD5, (unsigned char *)realm, strlen(realm));
280
+ MD5Update(&MD5, (unsigned char *)":", 1);
281
+ MD5Update(&MD5, (unsigned char *)password, strlen(password));
282
+ MD5Final(digest, &MD5);
283
+
284
+ /* digest now contains the first field of A1 */
285
+
286
+ MD5Init(&MD5);
287
+ MD5Update(&MD5, digest, 16);
288
+ MD5Update(&MD5, (unsigned char *)":", 1);
289
+ value = hash_get(table, "nonce");
290
+ MD5Update(&MD5, (unsigned char *)value, strlen(value));
291
+ MD5Update(&MD5, (unsigned char *)":", 1);
292
+ value = hash_get(table, "cnonce");
293
+ MD5Update(&MD5, (unsigned char *)value, strlen(value));
294
+ MD5Final(digest, &MD5);
295
+
296
+ /* now digest is MD5(A1) */
297
+ memcpy(HA1, digest, 16);
298
+
299
+ /* construct MD5(A2) */
300
+ MD5Init(&MD5);
301
+ MD5Update(&MD5, (unsigned char *)"AUTHENTICATE:", 13);
302
+ value = hash_get(table, "digest-uri");
303
+ MD5Update(&MD5, (unsigned char *)value, strlen(value));
304
+ if (strcmp(hash_get(table, "qop"), "auth") != 0) {
305
+ MD5Update(&MD5, (unsigned char *)":00000000000000000000000000000000",
306
+ 33);
307
+ }
308
+ MD5Final(digest, &MD5);
309
+
310
+ memcpy(HA2, digest, 16);
311
+
312
+ /* construct response */
313
+ MD5Init(&MD5);
314
+ _digest_to_hex((char *)HA1, hex);
315
+ MD5Update(&MD5, (unsigned char *)hex, 32);
316
+ MD5Update(&MD5, (unsigned char *)":", 1);
317
+ value = hash_get(table, "nonce");
318
+ MD5Update(&MD5, (unsigned char *)value, strlen(value));
319
+ MD5Update(&MD5, (unsigned char *)":", 1);
320
+ value = hash_get(table, "nc");
321
+ MD5Update(&MD5, (unsigned char *)value, strlen(value));
322
+ MD5Update(&MD5, (unsigned char *)":", 1);
323
+ value = hash_get(table, "cnonce");
324
+ MD5Update(&MD5, (unsigned char *)value, strlen(value));
325
+ MD5Update(&MD5, (unsigned char *)":", 1);
326
+ value = hash_get(table, "qop");
327
+ MD5Update(&MD5, (unsigned char *)value, strlen(value));
328
+ MD5Update(&MD5, (unsigned char *)":", 1);
329
+ _digest_to_hex((char *)HA2, hex);
330
+ MD5Update(&MD5, (unsigned char *)hex, 32);
331
+ MD5Final(digest, &MD5);
332
+
333
+ response = xmpp_alloc(ctx, 32+1);
334
+ _digest_to_hex((char *)digest, hex);
335
+ memcpy(response, hex, 32);
336
+ response[32] = '\0';
337
+ hash_add(table, "response", response);
338
+
339
+ /* construct reply */
340
+ result = NULL;
341
+ rlen = 0;
342
+ result = _add_key(ctx, table, "username", result, &rlen, 1);
343
+ result = _add_key(ctx, table, "realm", result, &rlen, 1);
344
+ result = _add_key(ctx, table, "nonce", result, &rlen, 1);
345
+ result = _add_key(ctx, table, "cnonce", result, &rlen, 1);
346
+ result = _add_key(ctx, table, "nc", result, &rlen, 0);
347
+ result = _add_key(ctx, table, "qop", result, &rlen, 0);
348
+ result = _add_key(ctx, table, "digest-uri", result, &rlen, 1);
349
+ result = _add_key(ctx, table, "response", result, &rlen, 0);
350
+ result = _add_key(ctx, table, "charset", result, &rlen, 0);
351
+
352
+ xmpp_free(ctx, node);
353
+ xmpp_free(ctx, domain);
354
+ hash_release(table); /* also frees value strings */
355
+
356
+ /* reuse response for the base64 encode of our result */
357
+ response = base64_encode(ctx, (unsigned char *)result, strlen(result));
358
+ xmpp_free(ctx, result);
359
+
360
+ return response;
361
+ }
362
+
363
+
364
+ /** Base64 encoding routines. Implemented according to RFC 3548 */
365
+
366
+ /** map of all byte values to the base64 values, or to
367
+ '65' which indicates an invalid character. '=' is '64' */
368
+ static const char _base64_invcharmap[256] = {
369
+ 65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
370
+ 65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
371
+ 65,65,65,65, 65,65,65,65, 65,65,65,62, 65,65,65,63,
372
+ 52,53,54,55, 56,57,58,59, 60,61,65,65, 65,64,65,65,
373
+ 65, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
374
+ 15,16,17,18, 19,20,21,22, 23,24,25,65, 65,65,65,65,
375
+ 65,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
376
+ 41,42,43,44, 45,46,47,48, 49,50,51,65, 65,65,65,65,
377
+ 65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
378
+ 65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
379
+ 65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
380
+ 65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
381
+ 65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
382
+ 65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
383
+ 65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
384
+ 65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65
385
+ };
386
+
387
+ /** map of all 6-bit values to their corresponding byte
388
+ in the base64 alphabet. Padding char is the value '64' */
389
+ static const char _base64_charmap[65] = {
390
+ 'A','B','C','D', 'E','F','G','H',
391
+ 'I','J','K','L', 'M','N','O','P',
392
+ 'Q','R','S','T', 'U','V','W','X',
393
+ 'Y','Z','a','b', 'c','d','e','f',
394
+ 'g','h','i','j', 'k','l','m','n',
395
+ 'o','p','q','r', 's','t','u','v',
396
+ 'w','x','y','z', '0','1','2','3',
397
+ '4','5','6','7', '8','9','+','/',
398
+ '='
399
+ };
400
+
401
+ int base64_encoded_len(xmpp_ctx_t *ctx, const unsigned len)
402
+ {
403
+ /* encoded steam is 4 bytes for every three, rounded up */
404
+ return ((len + 2)/3) << 2;
405
+ }
406
+
407
+ char *base64_encode(xmpp_ctx_t *ctx,
408
+ const unsigned char * const buffer, const unsigned len)
409
+ {
410
+ int clen;
411
+ char *cbuf, *c;
412
+ uint32_t word, hextet;
413
+ int i;
414
+
415
+ clen = base64_encoded_len(ctx, len);
416
+ cbuf = xmpp_alloc(ctx, clen + 1);
417
+ if (cbuf != NULL) {
418
+
419
+ int inlen = len;
420
+ int outlen = clen + 1;
421
+ const unsigned char* in = buffer;
422
+ char* out = cbuf;
423
+ static const char b64str[64] =
424
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
425
+
426
+ while (inlen && outlen)
427
+ {
428
+ *out++ = b64str[(in[0] >> 2) & 0x3f];
429
+ if (!--outlen)
430
+ break;
431
+ *out++ = b64str[((in[0] << 4)
432
+ + (--inlen ? in[1] >> 4 : 0))
433
+ & 0x3f];
434
+ if (!--outlen)
435
+ break;
436
+ *out++ =
437
+ (inlen
438
+ ? b64str[((in[1] << 2)
439
+ + (--inlen ? in[2] >> 6 : 0))
440
+ & 0x3f]
441
+ : '=');
442
+ if (!--outlen)
443
+ break;
444
+ *out++ = inlen ? b64str[in[2] & 0x3f] : '=';
445
+ if (!--outlen)
446
+ break;
447
+ if (inlen)
448
+ inlen--;
449
+ if (inlen)
450
+ in += 3;
451
+ }
452
+
453
+ if (outlen)
454
+ *out = '\0';
455
+ }
456
+
457
+ return cbuf;
458
+ }
459
+
460
+ int base64_decoded_len(xmpp_ctx_t *ctx,
461
+ const char * const buffer, const unsigned len)
462
+ {
463
+ int nudge;
464
+ int c;
465
+
466
+ /* count the padding characters for the remainder */
467
+ nudge = -1;
468
+ c = _base64_invcharmap[(int)buffer[len-1]];
469
+ if (c < 64) nudge = 0;
470
+ else if (c == 64) {
471
+ c = _base64_invcharmap[(int)buffer[len-2]];
472
+ if (c < 64) nudge = 1;
473
+ else if (c == 64) {
474
+ c = _base64_invcharmap[(int)buffer[len-3]];
475
+ if (c < 64) nudge = 2;
476
+ }
477
+ }
478
+ if (nudge < 0) return 0; /* reject bad coding */
479
+
480
+ /* decoded steam is 3 bytes for every four */
481
+ return 3 * (len >> 2) - nudge;
482
+ }
483
+
484
+ unsigned char *base64_decode(xmpp_ctx_t *ctx,
485
+ const char * const buffer, const unsigned len)
486
+ {
487
+ int dlen;
488
+ unsigned char *dbuf, *d;
489
+ uint32_t word, hextet;
490
+ int i;
491
+
492
+ /* len must be a multiple of 4 */
493
+ if (len & 0x03) return NULL;
494
+
495
+ dlen = base64_decoded_len(ctx, buffer, len);
496
+ dbuf = xmpp_alloc(ctx, dlen + 1);
497
+ if (dbuf != NULL) {
498
+ d = dbuf;
499
+ /* loop over each set of 4 characters, decoding 3 bytes */
500
+ for (i = 0; i < len - 3; i += 4) {
501
+ hextet = _base64_invcharmap[(int)buffer[i]];
502
+ if (hextet & 0xC0) break;
503
+ word = hextet << 18;
504
+ hextet = _base64_invcharmap[(int)buffer[i+1]];
505
+ if (hextet & 0xC0) break;
506
+ word |= hextet << 12;
507
+ hextet = _base64_invcharmap[(int)buffer[i+2]];
508
+ if (hextet & 0xC0) break;
509
+ word |= hextet << 6;
510
+ hextet = _base64_invcharmap[(int)buffer[i+3]];
511
+ if (hextet & 0xC0) break;
512
+ word |= hextet;
513
+ *d++ = (word & 0x00FF0000) >> 16;
514
+ *d++ = (word & 0x0000FF00) >> 8;
515
+ *d++ = (word & 0x000000FF);
516
+ }
517
+ if (hextet > 64) goto _base64_decode_error;
518
+ /* handle the remainder */
519
+ switch (dlen % 3) {
520
+ case 0:
521
+ /* nothing to do */
522
+ break;
523
+ case 1:
524
+ /* redo the last quartet, checking for correctness */
525
+ hextet = _base64_invcharmap[(int)buffer[len-4]];
526
+ if (hextet & 0xC0) goto _base64_decode_error;
527
+ word = hextet << 2;
528
+ hextet = _base64_invcharmap[(int)buffer[len-3]];
529
+ if (hextet & 0xC0) goto _base64_decode_error;
530
+ word |= hextet >> 4;
531
+ *d++ = word & 0xFF;
532
+ hextet = _base64_invcharmap[(int)buffer[len-2]];
533
+ if (hextet != 64) goto _base64_decode_error;
534
+ hextet = _base64_invcharmap[(int)buffer[len-1]];
535
+ if (hextet != 64) goto _base64_decode_error;
536
+ break;
537
+ case 2:
538
+ /* redo the last quartet, checking for correctness */
539
+ hextet = _base64_invcharmap[(int)buffer[len-4]];
540
+ if (hextet & 0xC0) goto _base64_decode_error;
541
+ word = hextet << 10;
542
+ hextet = _base64_invcharmap[(int)buffer[len-3]];
543
+ if (hextet & 0xC0) goto _base64_decode_error;
544
+ word |= hextet << 4;
545
+ hextet = _base64_invcharmap[(int)buffer[len-2]];
546
+ if (hextet & 0xC0) goto _base64_decode_error;
547
+ word |= hextet >> 2;
548
+ *d++ = (word & 0xFF00) >> 8;
549
+ *d++ = (word & 0x00FF);
550
+ hextet = _base64_invcharmap[(int)buffer[len-1]];
551
+ if (hextet != 64) goto _base64_decode_error;
552
+ break;
553
+ }
554
+ }
555
+ *d = '\0';
556
+ return dbuf;
557
+
558
+ _base64_decode_error:
559
+ /* invalid character; abort decoding! */
560
+ xmpp_free(ctx, dbuf);
561
+ return NULL;
562
+ }
563
+
564
+ /*** self tests ***/
565
+ #ifdef TEST
566
+
567
+ #include <stdio.h>
568
+
569
+ int test_charmap_identity(void)
570
+ {
571
+ int i, v, u;
572
+
573
+ for (i = 0; i < 65; i++) {
574
+ v = _base64_charmap[i];
575
+ if (v > 255) return 1;
576
+ u = _base64_invcharmap[v];
577
+ /* printf("map: %d -> %d -> %d\n", i, v, u); */
578
+ if (u != i) return 1;
579
+ }
580
+
581
+ return 0;
582
+ }
583
+
584
+ int test_charmap_range(void)
585
+ {
586
+ int i, v;
587
+
588
+ for (i = 64; i < 256; i++) {
589
+ v = _base64_invcharmap[i];
590
+ if (i < 64) return 1;
591
+ }
592
+
593
+ return 0;
594
+ }
595
+
596
+ int main(int argc, char *argv[])
597
+ {
598
+ int ret = 0;
599
+
600
+ printf("testing charmap identity...");
601
+ ret = test_charmap_identity();
602
+ if (ret) return ret;
603
+ printf(" ok.\n");
604
+
605
+ printf("testing charmap range...");
606
+ ret = test_charmap_range();
607
+ if (ret) return ret;
608
+ printf(" ok.\n");
609
+
610
+ printf("no error\n");
611
+ return 0;
612
+ }
613
+
614
+ #endif /* TEST */
data/ext/sasl.h ADDED
@@ -0,0 +1,44 @@
1
+ /* sasl.h
2
+ ** strophe XMPP client library -- SASL authentication helpers
3
+ **
4
+ ** Copyright (C) 2005-2008 OGG, LLC. All rights reserved.
5
+ **
6
+ ** This software is provided AS-IS with no warranty, either express
7
+ ** or 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
+ * SASL authentication helpers.
17
+ */
18
+
19
+ #ifndef __LIBSTROPHE_SASL_H__
20
+ #define __LIBSTROPHE_SASL_H__
21
+
22
+ #include "strophe.h"
23
+
24
+ /** low-level sasl routines */
25
+
26
+ char *sasl_plain(xmpp_ctx_t *ctx, const char *authid, const char *password);
27
+ char *sasl_digest_md5(xmpp_ctx_t *ctx, const char *challenge,
28
+ const char *jid, const char *password);
29
+
30
+
31
+ /** Base64 encoding routines. Implemented according to RFC 3548 */
32
+
33
+ int base64_encoded_len(xmpp_ctx_t *ctx, const unsigned len);
34
+
35
+ char *base64_encode(xmpp_ctx_t *ctx,
36
+ const unsigned char * const buffer, const unsigned len);
37
+
38
+ int base64_decoded_len(xmpp_ctx_t *ctx,
39
+ const char * const buffer, const unsigned len);
40
+
41
+ unsigned char *base64_decode(xmpp_ctx_t *ctx,
42
+ const char * const buffer, const unsigned len);
43
+
44
+ #endif /* _LIBXMPP_SASL_H__ */