comparison src/protocols/oscar/auth.c @ 7253:0ed4d53c46f9

[gaim-migrate @ 7830] I am slicing and dicing my way through culinary college. committer: Tailor Script <tailor@pidgin.im>
author Mark Doliner <mark@kingant.net>
date Tue, 14 Oct 2003 03:02:05 +0000
parents 6d3d8f11e765
children ad243bc63184
comparison
equal deleted inserted replaced
7252:1a808d72caff 7253:0ed4d53c46f9
9 #define FAIM_INTERNAL 9 #define FAIM_INTERNAL
10 #include <aim.h> 10 #include <aim.h>
11 11
12 #include "md5.h" 12 #include "md5.h"
13 13
14 static int aim_encode_password(const char *password, fu8_t *encoded); 14 /**
15 15 * Encode a password using old XOR method
16 /* 16 *
17 * This takes a const pointer to a (null terminated) string
18 * containing the unencoded password. It also gets passed
19 * an already allocated buffer to store the encoded password.
20 * This buffer should be the exact length of the password without
21 * the null. The encoded password buffer /is not %NULL terminated/.
22 *
23 * The encoding_table seems to be a fixed set of values. We'll
24 * hope it doesn't change over time!
25 *
26 * This is only used for the XOR method, not the better MD5 method.
27 *
28 * @param password Incoming password.
29 * @param encoded Buffer to put encoded password.
30 */
31 static int aim_encode_password(const char *password, fu8_t *encoded)
32 {
33 fu8_t encoding_table[] = {
34 #if 0 /* old v1 table */
35 0xf3, 0xb3, 0x6c, 0x99,
36 0x95, 0x3f, 0xac, 0xb6,
37 0xc5, 0xfa, 0x6b, 0x63,
38 0x69, 0x6c, 0xc3, 0x9f
39 #else /* v2.1 table, also works for ICQ */
40 0xf3, 0x26, 0x81, 0xc4,
41 0x39, 0x86, 0xdb, 0x92,
42 0x71, 0xa3, 0xb9, 0xe6,
43 0x53, 0x7a, 0x95, 0x7c
44 #endif
45 };
46 int i;
47
48 for (i = 0; i < strlen(password); i++)
49 encoded[i] = (password[i] ^ encoding_table[i]);
50
51 return 0;
52 }
53
54 #ifdef USE_OLD_MD5
55 static int aim_encode_password_md5(const char *password, const char *key, fu8_t *digest)
56 {
57 md5_state_t state;
58
59 md5_init(&state);
60 md5_append(&state, (const md5_byte_t *)key, strlen(key));
61 md5_append(&state, (const md5_byte_t *)password, strlen(password));
62 md5_append(&state, (const md5_byte_t *)AIM_MD5_STRING, strlen(AIM_MD5_STRING));
63 md5_finish(&state, (md5_byte_t *)digest);
64
65 return 0;
66 }
67 #else
68 static int aim_encode_password_md5(const char *password, const char *key, fu8_t *digest)
69 {
70 md5_state_t state;
71 fu8_t passdigest[16];
72
73 md5_init(&state);
74 md5_append(&state, (const md5_byte_t *)password, strlen(password));
75 md5_finish(&state, (md5_byte_t *)&passdigest);
76
77 md5_init(&state);
78 md5_append(&state, (const md5_byte_t *)key, strlen(key));
79 md5_append(&state, (const md5_byte_t *)&passdigest, 16);
80 md5_append(&state, (const md5_byte_t *)AIM_MD5_STRING, strlen(AIM_MD5_STRING));
81 md5_finish(&state, (md5_byte_t *)digest);
82
83 return 0;
84 }
85 #endif
86
87 /*
88 * Normally the FLAP version is sent as the first few bytes of the cookie,
89 * meaning you generally never call this.
90 *
91 * But there are times when something might want it seperate. Specifically,
92 * libfaim sends this internally when doing SNAC login.
93 *
94 */
95 faim_export int aim_sendflapver(aim_session_t *sess, aim_conn_t *conn)
96 {
97 aim_frame_t *fr;
98
99 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x01, 4)))
100 return -ENOMEM;
101
102 aimbs_put32(&fr->data, 0x00000001);
103
104 aim_tx_enqueue(sess, fr);
105
106 return 0;
107 }
108
109 /*
17 * This just pushes the passed cookie onto the passed connection, without 110 * This just pushes the passed cookie onto the passed connection, without
18 * the SNAC header or any of that. 111 * the SNAC header or any of that.
19 * 112 *
20 * Very commonly used, as every connection except auth will require this to 113 * Very commonly used, as every connection except auth will require this to
21 * be the first thing you send. 114 * be the first thing you send.
29 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x0001, 4+2+2+length))) 122 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x0001, 4+2+2+length)))
30 return -ENOMEM; 123 return -ENOMEM;
31 124
32 aimbs_put32(&fr->data, 0x00000001); 125 aimbs_put32(&fr->data, 0x00000001);
33 aim_tlvlist_add_raw(&tl, 0x0006, length, chipsahoy); 126 aim_tlvlist_add_raw(&tl, 0x0006, length, chipsahoy);
34 aim_tlvlist_write(&fr->data, &tl);
35 aim_tlvlist_free(&tl);
36
37 aim_tx_enqueue(sess, fr);
38
39 return 0;
40 }
41
42 /*
43 * Normally the FLAP version is sent as the first few bytes of the cookie,
44 * meaning you generally never call this.
45 *
46 * But there are times when something might want it seperate. Specifically,
47 * libfaim sends this internally when doing SNAC login.
48 *
49 */
50 faim_export int aim_sendflapver(aim_session_t *sess, aim_conn_t *conn)
51 {
52 aim_frame_t *fr;
53
54 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x01, 4)))
55 return -ENOMEM;
56
57 aimbs_put32(&fr->data, 0x00000001);
58
59 aim_tx_enqueue(sess, fr);
60
61 return 0;
62 }
63
64 /*
65 * This is a bit confusing.
66 *
67 * Normal SNAC login goes like this:
68 * - connect
69 * - server sends flap version
70 * - client sends flap version
71 * - client sends screen name (17/6)
72 * - server sends hash key (17/7)
73 * - client sends auth request (17/2 -- aim_send_login)
74 * - server yells
75 *
76 * XOR login (for ICQ) goes like this:
77 * - connect
78 * - server sends flap version
79 * - client sends auth request which contains flap version (aim_send_login)
80 * - server yells
81 *
82 * For the client API, we make them implement the most complicated version,
83 * and for the simpler version, we fake it and make it look like the more
84 * complicated process.
85 *
86 * This is done by giving the client a faked key, just so we can convince
87 * them to call aim_send_login right away, which will detect the session
88 * flag that says this is XOR login and ignore the key, sending an ICQ
89 * login request instead of the normal SNAC one.
90 *
91 * As soon as AOL makes ICQ log in the same way as AIM, this is /gone/.
92 *
93 * XXX This may cause problems if the client relies on callbacks only
94 * being called from the context of aim_rxdispatch()...
95 *
96 */
97 static int goddamnicq(aim_session_t *sess, aim_conn_t *conn, const char *sn)
98 {
99 aim_frame_t fr;
100 aim_rxcallback_t userfunc;
101
102 sess->flags &= ~AIM_SESS_FLAGS_SNACLOGIN;
103 sess->flags |= AIM_SESS_FLAGS_XORLOGIN;
104
105 fr.conn = conn;
106
107 if ((userfunc = aim_callhandler(sess, conn, 0x0017, 0x0007)))
108 userfunc(sess, &fr, "");
109
110 return 0;
111 }
112
113 /*
114 * In AIM 3.5 protocol, the first stage of login is to request login from the
115 * Authorizer, passing it the screen name for verification. If the name is
116 * invalid, a 0017/0003 is spit back, with the standard error contents. If
117 * valid, a 0017/0007 comes back, which is the signal to send it the main
118 * login command (0017/0002).
119 *
120 */
121 faim_export int aim_request_login(aim_session_t *sess, aim_conn_t *conn, const char *sn)
122 {
123 aim_frame_t *fr;
124 aim_snacid_t snacid;
125 aim_tlvlist_t *tl = NULL;
126
127 if (!sess || !conn || !sn)
128 return -EINVAL;
129
130 if ((sn[0] >= '0') && (sn[0] <= '9'))
131 return goddamnicq(sess, conn, sn);
132
133 sess->flags |= AIM_SESS_FLAGS_SNACLOGIN;
134
135 aim_sendflapver(sess, conn);
136
137 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+2+2+strlen(sn))))
138 return -ENOMEM;
139
140 snacid = aim_cachesnac(sess, 0x0017, 0x0006, 0x0000, NULL, 0);
141 aim_putsnac(&fr->data, 0x0017, 0x0006, 0x0000, snacid);
142
143 aim_tlvlist_add_raw(&tl, 0x0001, strlen(sn), sn);
144 aim_tlvlist_write(&fr->data, &tl); 127 aim_tlvlist_write(&fr->data, &tl);
145 aim_tlvlist_free(&tl); 128 aim_tlvlist_free(&tl);
146 129
147 aim_tx_enqueue(sess, fr); 130 aim_tx_enqueue(sess, fr);
148 131
196 179
197 return 0; 180 return 0;
198 } 181 }
199 182
200 /* 183 /*
184 * Subtype 0x0002
185 *
201 * send_login(int socket, char *sn, char *password) 186 * send_login(int socket, char *sn, char *password)
202 * 187 *
203 * This is the initial login request packet. 188 * This is the initial login request packet.
204 * 189 *
205 * NOTE!! If you want/need to make use of the aim_sendmemblock() function, 190 * NOTE!! If you want/need to make use of the aim_sendmemblock() function,
237 return -EINVAL; 222 return -EINVAL;
238 223
239 /* 224 /*
240 * What the XORLOGIN flag _really_ means is that its an ICQ login, 225 * What the XORLOGIN flag _really_ means is that its an ICQ login,
241 * which is really stupid and painful, so its not done here. 226 * which is really stupid and painful, so its not done here.
242 *
243 */ 227 */
244 if (sess->flags & AIM_SESS_FLAGS_XORLOGIN) 228 if (sess->flags & AIM_SESS_FLAGS_XORLOGIN)
245 return goddamnicq2(sess, conn, sn, password, ci); 229 return goddamnicq2(sess, conn, sn, password, ci);
246 230
247
248 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152))) 231 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152)))
249 return -ENOMEM; 232 return -ENOMEM;
250 233
251 snacid = aim_cachesnac(sess, 0x0017, 0x0002, 0x0000, NULL, 0); 234 snacid = aim_cachesnac(sess, 0x0017, 0x0002, 0x0000, NULL, 0);
252 aim_putsnac(&fr->data, 0x0017, 0x0002, 0x0000, snacid); 235 aim_putsnac(&fr->data, 0x0017, 0x0002, 0x0000, snacid);
254 aim_tlvlist_add_raw(&tl, 0x0001, strlen(sn), sn); 237 aim_tlvlist_add_raw(&tl, 0x0001, strlen(sn), sn);
255 238
256 aim_encode_password_md5(password, key, digest); 239 aim_encode_password_md5(password, key, digest);
257 aim_tlvlist_add_raw(&tl, 0x0025, 16, digest); 240 aim_tlvlist_add_raw(&tl, 0x0025, 16, digest);
258 241
259 /* 242 #ifndef USE_OLD_MD5
260 * Newer versions of winaim have an empty type x004c TLV here. 243 aim_tlvlist_add_noval(&tl, 0x004c);
261 */ 244 #endif
262 245
263 if (ci->clientstring) 246 if (ci->clientstring)
264 aim_tlvlist_add_raw(&tl, 0x0003, strlen(ci->clientstring), ci->clientstring); 247 aim_tlvlist_add_raw(&tl, 0x0003, strlen(ci->clientstring), ci->clientstring);
265 aim_tlvlist_add_16(&tl, 0x0016, (fu16_t)ci->clientid); 248 aim_tlvlist_add_16(&tl, 0x0016, (fu16_t)ci->clientid);
266 aim_tlvlist_add_16(&tl, 0x0017, (fu16_t)ci->major); 249 aim_tlvlist_add_16(&tl, 0x0017, (fu16_t)ci->major);
267 aim_tlvlist_add_16(&tl, 0x0018, (fu16_t)ci->minor); 250 aim_tlvlist_add_16(&tl, 0x0018, (fu16_t)ci->minor);
268 aim_tlvlist_add_16(&tl, 0x0019, (fu16_t)ci->point); 251 aim_tlvlist_add_16(&tl, 0x0019, (fu16_t)ci->point);
269 aim_tlvlist_add_16(&tl, 0x001a, (fu16_t)ci->build); 252 aim_tlvlist_add_16(&tl, 0x001a, (fu16_t)ci->build);
270 aim_tlvlist_add_32(&tl, 0x0014, (fu32_t)ci->distrib); 253 aim_tlvlist_add_32(&tl, 0x0014, (fu32_t)ci->distrib);
254 aim_tlvlist_add_raw(&tl, 0x000f, strlen(ci->lang), ci->lang);
271 aim_tlvlist_add_raw(&tl, 0x000e, strlen(ci->country), ci->country); 255 aim_tlvlist_add_raw(&tl, 0x000e, strlen(ci->country), ci->country);
272 aim_tlvlist_add_raw(&tl, 0x000f, strlen(ci->lang), ci->lang);
273 256
274 #ifndef NOSSI 257 #ifndef NOSSI
275 /* 258 /*
276 * If set, old-fashioned buddy lists will not work. You will need 259 * If set, old-fashioned buddy lists will not work. You will need
277 * to use SSI. 260 * to use SSI.
282 aim_tlvlist_write(&fr->data, &tl); 265 aim_tlvlist_write(&fr->data, &tl);
283 266
284 aim_tlvlist_free(&tl); 267 aim_tlvlist_free(&tl);
285 268
286 aim_tx_enqueue(sess, fr); 269 aim_tx_enqueue(sess, fr);
287
288 return 0;
289 }
290
291 faim_export int aim_encode_password_md5(const char *password, const char *key, fu8_t *digest)
292 {
293 md5_state_t state;
294
295 md5_init(&state);
296 md5_append(&state, (const md5_byte_t *)key, strlen(key));
297 md5_append(&state, (const md5_byte_t *)password, strlen(password));
298 md5_append(&state, (const md5_byte_t *)AIM_MD5_STRING, strlen(AIM_MD5_STRING));
299 md5_finish(&state, (md5_byte_t *)digest);
300
301 return 0;
302 }
303
304 /**
305 * aim_encode_password - Encode a password using old XOR method
306 * @password: incoming password
307 * @encoded: buffer to put encoded password
308 *
309 * This takes a const pointer to a (null terminated) string
310 * containing the unencoded password. It also gets passed
311 * an already allocated buffer to store the encoded password.
312 * This buffer should be the exact length of the password without
313 * the null. The encoded password buffer /is not %NULL terminated/.
314 *
315 * The encoding_table seems to be a fixed set of values. We'll
316 * hope it doesn't change over time!
317 *
318 * This is only used for the XOR method, not the better MD5 method.
319 *
320 */
321 static int aim_encode_password(const char *password, fu8_t *encoded)
322 {
323 fu8_t encoding_table[] = {
324 #if 0 /* old v1 table */
325 0xf3, 0xb3, 0x6c, 0x99,
326 0x95, 0x3f, 0xac, 0xb6,
327 0xc5, 0xfa, 0x6b, 0x63,
328 0x69, 0x6c, 0xc3, 0x9f
329 #else /* v2.1 table, also works for ICQ */
330 0xf3, 0x26, 0x81, 0xc4,
331 0x39, 0x86, 0xdb, 0x92,
332 0x71, 0xa3, 0xb9, 0xe6,
333 0x53, 0x7a, 0x95, 0x7c
334 #endif
335 };
336 int i;
337
338 for (i = 0; i < strlen(password); i++)
339 encoded[i] = (password[i] ^ encoding_table[i]);
340 270
341 return 0; 271 return 0;
342 } 272 }
343 273
344 /* 274 /*
436 if (aim_tlv_gettlv(tlvlist, 0x0042, 1)) 366 if (aim_tlv_gettlv(tlvlist, 0x0042, 1))
437 info->latestbeta.info = aim_tlv_getstr(tlvlist, 0x0042, 1); 367 info->latestbeta.info = aim_tlv_getstr(tlvlist, 0x0042, 1);
438 if (aim_tlv_gettlv(tlvlist, 0x0043, 1)) 368 if (aim_tlv_gettlv(tlvlist, 0x0043, 1))
439 info->latestbeta.name = aim_tlv_getstr(tlvlist, 0x0043, 1); 369 info->latestbeta.name = aim_tlv_getstr(tlvlist, 0x0043, 1);
440 if (aim_tlv_gettlv(tlvlist, 0x0048, 1)) 370 if (aim_tlv_gettlv(tlvlist, 0x0048, 1))
441 ; /* no idea what this is */ 371 ; /* beta serial */
442 372
443 if (aim_tlv_gettlv(tlvlist, 0x0044, 1)) 373 if (aim_tlv_gettlv(tlvlist, 0x0044, 1))
444 info->latestrelease.build = aim_tlv_get32(tlvlist, 0x0044, 1); 374 info->latestrelease.build = aim_tlv_get32(tlvlist, 0x0044, 1);
445 if (aim_tlv_gettlv(tlvlist, 0x0045, 1)) 375 if (aim_tlv_gettlv(tlvlist, 0x0045, 1))
446 info->latestrelease.url = aim_tlv_getstr(tlvlist, 0x0045, 1); 376 info->latestrelease.url = aim_tlv_getstr(tlvlist, 0x0045, 1);
447 if (aim_tlv_gettlv(tlvlist, 0x0046, 1)) 377 if (aim_tlv_gettlv(tlvlist, 0x0046, 1))
448 info->latestrelease.info = aim_tlv_getstr(tlvlist, 0x0046, 1); 378 info->latestrelease.info = aim_tlv_getstr(tlvlist, 0x0046, 1);
449 if (aim_tlv_gettlv(tlvlist, 0x0047, 1)) 379 if (aim_tlv_gettlv(tlvlist, 0x0047, 1))
450 info->latestrelease.name = aim_tlv_getstr(tlvlist, 0x0047, 1); 380 info->latestrelease.name = aim_tlv_getstr(tlvlist, 0x0047, 1);
451 if (aim_tlv_gettlv(tlvlist, 0x0049, 1)) 381 if (aim_tlv_gettlv(tlvlist, 0x0049, 1))
452 ; /* no idea what this is */ 382 ; /* lastest release serial */
453 383
454 /* 384 /*
455 * URL to change password. 385 * URL to change password.
456 */ 386 */
457 if (aim_tlv_gettlv(tlvlist, 0x0054, 1)) 387 if (aim_tlv_gettlv(tlvlist, 0x0054, 1))
472 402
473 return ret; 403 return ret;
474 } 404 }
475 405
476 /* 406 /*
407 * Subtype 0x0007 (kind of) - Send a fake type 0x0007 SNAC to the client
408 *
409 * This is a bit confusing.
410 *
411 * Normal SNAC login goes like this:
412 * - connect
413 * - server sends flap version
414 * - client sends flap version
415 * - client sends screen name (17/6)
416 * - server sends hash key (17/7)
417 * - client sends auth request (17/2 -- aim_send_login)
418 * - server yells
419 *
420 * XOR login (for ICQ) goes like this:
421 * - connect
422 * - server sends flap version
423 * - client sends auth request which contains flap version (aim_send_login)
424 * - server yells
425 *
426 * For the client API, we make them implement the most complicated version,
427 * and for the simpler version, we fake it and make it look like the more
428 * complicated process.
429 *
430 * This is done by giving the client a faked key, just so we can convince
431 * them to call aim_send_login right away, which will detect the session
432 * flag that says this is XOR login and ignore the key, sending an ICQ
433 * login request instead of the normal SNAC one.
434 *
435 * As soon as AOL makes ICQ log in the same way as AIM, this is /gone/.
436 *
437 * XXX This may cause problems if the client relies on callbacks only
438 * being called from the context of aim_rxdispatch()...
439 *
440 */
441 static int goddamnicq(aim_session_t *sess, aim_conn_t *conn, const char *sn)
442 {
443 aim_frame_t fr;
444 aim_rxcallback_t userfunc;
445
446 sess->flags &= ~AIM_SESS_FLAGS_SNACLOGIN;
447 sess->flags |= AIM_SESS_FLAGS_XORLOGIN;
448
449 fr.conn = conn;
450
451 if ((userfunc = aim_callhandler(sess, conn, 0x0017, 0x0007)))
452 userfunc(sess, &fr, "");
453
454 return 0;
455 }
456
457 /*
458 * Subtype 0x0006
459 *
460 * In AIM 3.5 protocol, the first stage of login is to request login from the
461 * Authorizer, passing it the screen name for verification. If the name is
462 * invalid, a 0017/0003 is spit back, with the standard error contents. If
463 * valid, a 0017/0007 comes back, which is the signal to send it the main
464 * login command (0017/0002).
465 *
466 */
467 faim_export int aim_request_login(aim_session_t *sess, aim_conn_t *conn, const char *sn)
468 {
469 aim_frame_t *fr;
470 aim_snacid_t snacid;
471 aim_tlvlist_t *tl = NULL;
472
473 if (!sess || !conn || !sn)
474 return -EINVAL;
475
476 if ((sn[0] >= '0') && (sn[0] <= '9'))
477 return goddamnicq(sess, conn, sn);
478
479 sess->flags |= AIM_SESS_FLAGS_SNACLOGIN;
480
481 aim_sendflapver(sess, conn);
482
483 if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+2+2+strlen(sn) /*+8*/ )))
484 return -ENOMEM;
485
486 snacid = aim_cachesnac(sess, 0x0017, 0x0006, 0x0000, NULL, 0);
487 aim_putsnac(&fr->data, 0x0017, 0x0006, 0x0000, snacid);
488
489 aim_tlvlist_add_raw(&tl, 0x0001, strlen(sn), sn);
490 /* aim_tlvlist_add_noval(&tl, 0x004b);
491 aim_tlvlist_add_noval(&tl, 0x005a); */
492 aim_tlvlist_write(&fr->data, &tl);
493 aim_tlvlist_free(&tl);
494
495 aim_tx_enqueue(sess, fr);
496
497 return 0;
498 }
499
500 /*
501 * Subtype 0x0007
502 *
477 * Middle handler for 0017/0007 SNACs. Contains the auth key prefixed 503 * Middle handler for 0017/0007 SNACs. Contains the auth key prefixed
478 * by only its length in a two byte word. 504 * by only its length in a two byte word.
479 * 505 *
480 * Calls the client, which should then use the value to call aim_send_login. 506 * Calls the client, which should then use the value to call aim_send_login.
481 * 507 *