Mercurial > pidgin
comparison libpurple/protocols/oscar/family_auth.c @ 15373:5fe8042783c1
Rename gtk/ and libgaim/ to pidgin/ and libpurple/
author | Sean Egan <seanegan@gmail.com> |
---|---|
date | Sat, 20 Jan 2007 02:32:10 +0000 |
parents | |
children | 32c366eeeb99 |
comparison
equal
deleted
inserted
replaced
15372:f79e0f4df793 | 15373:5fe8042783c1 |
---|---|
1 /* | |
2 * Gaim's oscar protocol plugin | |
3 * This file is the legal property of its developers. | |
4 * Please see the AUTHORS file distributed alongside this file. | |
5 * | |
6 * This library is free software; you can redistribute it and/or | |
7 * modify it under the terms of the GNU Lesser General Public | |
8 * License as published by the Free Software Foundation; either | |
9 * version 2 of the License, or (at your option) any later version. | |
10 * | |
11 * This library is distributed in the hope that it will be useful, | |
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 * Lesser General Public License for more details. | |
15 * | |
16 * You should have received a copy of the GNU Lesser General Public | |
17 * License along with this library; if not, write to the Free Software | |
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
19 */ | |
20 | |
21 /* | |
22 * Family 0x0017 - Authentication. | |
23 * | |
24 * Deals with the authorizer for SNAC-based login, and also old-style | |
25 * non-SNAC login. | |
26 * | |
27 */ | |
28 | |
29 #include "oscar.h" | |
30 | |
31 #include "cipher.h" | |
32 | |
33 #include <ctype.h> | |
34 | |
35 #define USE_XOR_FOR_ICQ | |
36 | |
37 #ifdef USE_XOR_FOR_ICQ | |
38 /** | |
39 * Encode a password using old XOR method | |
40 * | |
41 * This takes a const pointer to a (null terminated) string | |
42 * containing the unencoded password. It also gets passed | |
43 * an already allocated buffer to store the encoded password. | |
44 * This buffer should be the exact length of the password without | |
45 * the null. The encoded password buffer /is not %NULL terminated/. | |
46 * | |
47 * The encoding_table seems to be a fixed set of values. We'll | |
48 * hope it doesn't change over time! | |
49 * | |
50 * This is only used for the XOR method, not the better MD5 method. | |
51 * | |
52 * @param password Incoming password. | |
53 * @param encoded Buffer to put encoded password. | |
54 */ | |
55 static int | |
56 aim_encode_password(const char *password, guint8 *encoded) | |
57 { | |
58 guint8 encoding_table[] = { | |
59 #if 0 /* old v1 table */ | |
60 0xf3, 0xb3, 0x6c, 0x99, | |
61 0x95, 0x3f, 0xac, 0xb6, | |
62 0xc5, 0xfa, 0x6b, 0x63, | |
63 0x69, 0x6c, 0xc3, 0x9f | |
64 #else /* v2.1 table, also works for ICQ */ | |
65 0xf3, 0x26, 0x81, 0xc4, | |
66 0x39, 0x86, 0xdb, 0x92, | |
67 0x71, 0xa3, 0xb9, 0xe6, | |
68 0x53, 0x7a, 0x95, 0x7c | |
69 #endif | |
70 }; | |
71 unsigned int i; | |
72 | |
73 for (i = 0; i < strlen(password); i++) | |
74 encoded[i] = (password[i] ^ encoding_table[i]); | |
75 | |
76 return 0; | |
77 } | |
78 #endif | |
79 | |
80 #ifdef USE_OLD_MD5 | |
81 static int | |
82 aim_encode_password_md5(const char *password, const char *key, guint8 *digest) | |
83 { | |
84 GaimCipher *cipher; | |
85 GaimCipherContext *context; | |
86 | |
87 cipher = gaim_ciphers_find_cipher("md5"); | |
88 | |
89 context = gaim_cipher_context_new(cipher, NULL); | |
90 gaim_cipher_context_append(context, (const guchar *)key, strlen(key)); | |
91 gaim_cipher_context_append(context, (const guchar *)password, strlen(password)); | |
92 gaim_cipher_context_append(context, (const guchar *)AIM_MD5_STRING, strlen(AIM_MD5_STRING)); | |
93 gaim_cipher_context_digest(context, 16, digest, NULL); | |
94 gaim_cipher_context_destroy(context); | |
95 | |
96 return 0; | |
97 } | |
98 #else | |
99 static int | |
100 aim_encode_password_md5(const char *password, const char *key, guint8 *digest) | |
101 { | |
102 GaimCipher *cipher; | |
103 GaimCipherContext *context; | |
104 guchar passdigest[16]; | |
105 | |
106 cipher = gaim_ciphers_find_cipher("md5"); | |
107 | |
108 context = gaim_cipher_context_new(cipher, NULL); | |
109 gaim_cipher_context_append(context, (const guchar *)password, strlen(password)); | |
110 gaim_cipher_context_digest(context, 16, passdigest, NULL); | |
111 gaim_cipher_context_destroy(context); | |
112 | |
113 context = gaim_cipher_context_new(cipher, NULL); | |
114 gaim_cipher_context_append(context, (const guchar *)key, strlen(key)); | |
115 gaim_cipher_context_append(context, passdigest, 16); | |
116 gaim_cipher_context_append(context, (const guchar *)AIM_MD5_STRING, strlen(AIM_MD5_STRING)); | |
117 gaim_cipher_context_digest(context, 16, digest, NULL); | |
118 gaim_cipher_context_destroy(context); | |
119 | |
120 return 0; | |
121 } | |
122 #endif | |
123 | |
124 #ifdef USE_XOR_FOR_ICQ | |
125 /* | |
126 * Part two of the ICQ hack. Note the ignoring of the key. | |
127 */ | |
128 static int | |
129 goddamnicq2(OscarData *od, FlapConnection *conn, const char *sn, const char *password, ClientInfo *ci) | |
130 { | |
131 FlapFrame *frame; | |
132 aim_tlvlist_t *tl = NULL; | |
133 int passwdlen; | |
134 guint8 *password_encoded; | |
135 | |
136 passwdlen = strlen(password); | |
137 password_encoded = (guint8 *)malloc(passwdlen+1); | |
138 if (passwdlen > MAXICQPASSLEN) | |
139 passwdlen = MAXICQPASSLEN; | |
140 | |
141 frame = flap_frame_new(od, 0x01, 1152); | |
142 | |
143 aim_encode_password(password, password_encoded); | |
144 | |
145 byte_stream_put32(&frame->data, 0x00000001); /* FLAP Version */ | |
146 aim_tlvlist_add_str(&tl, 0x0001, sn); | |
147 aim_tlvlist_add_raw(&tl, 0x0002, passwdlen, password_encoded); | |
148 | |
149 if (ci->clientstring) | |
150 aim_tlvlist_add_str(&tl, 0x0003, ci->clientstring); | |
151 aim_tlvlist_add_16(&tl, 0x0016, (guint16)ci->clientid); | |
152 aim_tlvlist_add_16(&tl, 0x0017, (guint16)ci->major); | |
153 aim_tlvlist_add_16(&tl, 0x0018, (guint16)ci->minor); | |
154 aim_tlvlist_add_16(&tl, 0x0019, (guint16)ci->point); | |
155 aim_tlvlist_add_16(&tl, 0x001a, (guint16)ci->build); | |
156 aim_tlvlist_add_32(&tl, 0x0014, (guint32)ci->distrib); /* distribution chan */ | |
157 aim_tlvlist_add_str(&tl, 0x000f, ci->lang); | |
158 aim_tlvlist_add_str(&tl, 0x000e, ci->country); | |
159 | |
160 aim_tlvlist_write(&frame->data, &tl); | |
161 | |
162 free(password_encoded); | |
163 aim_tlvlist_free(&tl); | |
164 | |
165 flap_connection_send(conn, frame); | |
166 | |
167 return 0; | |
168 } | |
169 #endif | |
170 | |
171 /* | |
172 * Subtype 0x0002 | |
173 * | |
174 * This is the initial login request packet. | |
175 * | |
176 * NOTE!! If you want/need to make use of the aim_sendmemblock() function, | |
177 * then the client information you send here must exactly match the | |
178 * executable that you're pulling the data from. | |
179 * | |
180 * Java AIM 1.1.19: | |
181 * clientstring = "AOL Instant Messenger (TM) version 1.1.19 for Java built 03/24/98, freeMem 215871 totalMem 1048567, i686, Linus, #2 SMP Sun Feb 11 03:41:17 UTC 2001 2.4.1-ac9, IBM Corporation, 1.1.8, 45.3, Tue Mar 27 12:09:17 PST 2001" | |
182 * clientid = 0x0001 | |
183 * major = 0x0001 | |
184 * minor = 0x0001 | |
185 * point = (not sent) | |
186 * build = 0x0013 | |
187 * unknown= (not sent) | |
188 * | |
189 * AIM for Linux 1.1.112: | |
190 * clientstring = "AOL Instant Messenger (SM)" | |
191 * clientid = 0x1d09 | |
192 * major = 0x0001 | |
193 * minor = 0x0001 | |
194 * point = 0x0001 | |
195 * build = 0x0070 | |
196 * unknown= 0x0000008b | |
197 * serverstore = 0x01 | |
198 * | |
199 */ | |
200 int | |
201 aim_send_login(OscarData *od, FlapConnection *conn, const char *sn, const char *password, ClientInfo *ci, const char *key) | |
202 { | |
203 FlapFrame *frame; | |
204 aim_tlvlist_t *tl = NULL; | |
205 guint8 digest[16]; | |
206 aim_snacid_t snacid; | |
207 | |
208 if (!ci || !sn || !password) | |
209 return -EINVAL; | |
210 | |
211 #ifdef USE_XOR_FOR_ICQ | |
212 /* If we're signing on an ICQ account then use the older, XOR login method */ | |
213 if (isdigit(sn[0])) | |
214 return goddamnicq2(od, conn, sn, password, ci); | |
215 #endif | |
216 | |
217 frame = flap_frame_new(od, 0x02, 1152); | |
218 | |
219 snacid = aim_cachesnac(od, 0x0017, 0x0002, 0x0000, NULL, 0); | |
220 aim_putsnac(&frame->data, 0x0017, 0x0002, 0x0000, snacid); | |
221 | |
222 aim_tlvlist_add_str(&tl, 0x0001, sn); | |
223 | |
224 /* Truncate ICQ passwords, if necessary */ | |
225 if (isdigit(sn[0]) && (strlen(password) > MAXICQPASSLEN)) | |
226 { | |
227 char truncated[MAXICQPASSLEN + 1]; | |
228 strncpy(truncated, password, MAXICQPASSLEN); | |
229 truncated[MAXICQPASSLEN] = 0; | |
230 aim_encode_password_md5(truncated, key, digest); | |
231 } | |
232 else | |
233 { | |
234 aim_encode_password_md5(password, key, digest); | |
235 } | |
236 | |
237 aim_tlvlist_add_raw(&tl, 0x0025, 16, digest); | |
238 | |
239 #ifndef USE_OLD_MD5 | |
240 aim_tlvlist_add_noval(&tl, 0x004c); | |
241 #endif | |
242 | |
243 if (ci->clientstring) | |
244 aim_tlvlist_add_str(&tl, 0x0003, ci->clientstring); | |
245 aim_tlvlist_add_16(&tl, 0x0016, (guint16)ci->clientid); | |
246 aim_tlvlist_add_16(&tl, 0x0017, (guint16)ci->major); | |
247 aim_tlvlist_add_16(&tl, 0x0018, (guint16)ci->minor); | |
248 aim_tlvlist_add_16(&tl, 0x0019, (guint16)ci->point); | |
249 aim_tlvlist_add_16(&tl, 0x001a, (guint16)ci->build); | |
250 aim_tlvlist_add_32(&tl, 0x0014, (guint32)ci->distrib); | |
251 aim_tlvlist_add_str(&tl, 0x000f, ci->lang); | |
252 aim_tlvlist_add_str(&tl, 0x000e, ci->country); | |
253 | |
254 /* | |
255 * If set, old-fashioned buddy lists will not work. You will need | |
256 * to use SSI. | |
257 */ | |
258 aim_tlvlist_add_8(&tl, 0x004a, 0x01); | |
259 | |
260 aim_tlvlist_write(&frame->data, &tl); | |
261 | |
262 aim_tlvlist_free(&tl); | |
263 | |
264 flap_connection_send(conn, frame); | |
265 | |
266 return 0; | |
267 } | |
268 | |
269 /* | |
270 * This is sent back as a general response to the login command. | |
271 * It can be either an error or a success, depending on the | |
272 * presence of certain TLVs. | |
273 * | |
274 * The client should check the value passed as errorcode. If | |
275 * its nonzero, there was an error. | |
276 */ | |
277 static int | |
278 parse(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) | |
279 { | |
280 aim_tlvlist_t *tlvlist; | |
281 aim_rxcallback_t userfunc; | |
282 struct aim_authresp_info *info; | |
283 int ret = 0; | |
284 | |
285 info = g_new0(struct aim_authresp_info, 1); | |
286 | |
287 /* | |
288 * Read block of TLVs. All further data is derived | |
289 * from what is parsed here. | |
290 */ | |
291 tlvlist = aim_tlvlist_read(bs); | |
292 | |
293 /* | |
294 * No matter what, we should have a screen name. | |
295 */ | |
296 memset(od->sn, 0, sizeof(od->sn)); | |
297 if (aim_tlv_gettlv(tlvlist, 0x0001, 1)) { | |
298 info->sn = aim_tlv_getstr(tlvlist, 0x0001, 1); | |
299 strncpy(od->sn, info->sn, sizeof(od->sn)); | |
300 } | |
301 | |
302 /* | |
303 * Check for an error code. If so, we should also | |
304 * have an error url. | |
305 */ | |
306 if (aim_tlv_gettlv(tlvlist, 0x0008, 1)) | |
307 info->errorcode = aim_tlv_get16(tlvlist, 0x0008, 1); | |
308 if (aim_tlv_gettlv(tlvlist, 0x0004, 1)) | |
309 info->errorurl = aim_tlv_getstr(tlvlist, 0x0004, 1); | |
310 | |
311 /* | |
312 * BOS server address. | |
313 */ | |
314 if (aim_tlv_gettlv(tlvlist, 0x0005, 1)) | |
315 info->bosip = aim_tlv_getstr(tlvlist, 0x0005, 1); | |
316 | |
317 /* | |
318 * Authorization cookie. | |
319 */ | |
320 if (aim_tlv_gettlv(tlvlist, 0x0006, 1)) { | |
321 aim_tlv_t *tmptlv; | |
322 | |
323 tmptlv = aim_tlv_gettlv(tlvlist, 0x0006, 1); | |
324 if (tmptlv != NULL) | |
325 { | |
326 info->cookielen = tmptlv->length; | |
327 info->cookie = tmptlv->value; | |
328 } | |
329 } | |
330 | |
331 /* | |
332 * The email address attached to this account | |
333 * Not available for ICQ or @mac.com logins. | |
334 * If you receive this TLV, then you are allowed to use | |
335 * family 0x0018 to check the status of your email. | |
336 * XXX - Not really true! | |
337 */ | |
338 if (aim_tlv_gettlv(tlvlist, 0x0011, 1)) | |
339 info->email = aim_tlv_getstr(tlvlist, 0x0011, 1); | |
340 | |
341 /* | |
342 * The registration status. (Not real sure what it means.) | |
343 * Not available for ICQ or @mac.com logins. | |
344 * | |
345 * 1 = No disclosure | |
346 * 2 = Limited disclosure | |
347 * 3 = Full disclosure | |
348 * | |
349 * This has to do with whether your email address is available | |
350 * to other users or not. AFAIK, this feature is no longer used. | |
351 * | |
352 * Means you can use the admin family? (0x0007) | |
353 * | |
354 */ | |
355 if (aim_tlv_gettlv(tlvlist, 0x0013, 1)) | |
356 info->regstatus = aim_tlv_get16(tlvlist, 0x0013, 1); | |
357 | |
358 if (aim_tlv_gettlv(tlvlist, 0x0040, 1)) | |
359 info->latestbeta.build = aim_tlv_get32(tlvlist, 0x0040, 1); | |
360 if (aim_tlv_gettlv(tlvlist, 0x0041, 1)) | |
361 info->latestbeta.url = aim_tlv_getstr(tlvlist, 0x0041, 1); | |
362 if (aim_tlv_gettlv(tlvlist, 0x0042, 1)) | |
363 info->latestbeta.info = aim_tlv_getstr(tlvlist, 0x0042, 1); | |
364 if (aim_tlv_gettlv(tlvlist, 0x0043, 1)) | |
365 info->latestbeta.name = aim_tlv_getstr(tlvlist, 0x0043, 1); | |
366 | |
367 #if 0 | |
368 if (aim_tlv_gettlv(tlvlist, 0x0048, 1)) { | |
369 /* beta serial */ | |
370 } | |
371 #endif | |
372 | |
373 if (aim_tlv_gettlv(tlvlist, 0x0044, 1)) | |
374 info->latestrelease.build = aim_tlv_get32(tlvlist, 0x0044, 1); | |
375 if (aim_tlv_gettlv(tlvlist, 0x0045, 1)) | |
376 info->latestrelease.url = aim_tlv_getstr(tlvlist, 0x0045, 1); | |
377 if (aim_tlv_gettlv(tlvlist, 0x0046, 1)) | |
378 info->latestrelease.info = aim_tlv_getstr(tlvlist, 0x0046, 1); | |
379 if (aim_tlv_gettlv(tlvlist, 0x0047, 1)) | |
380 info->latestrelease.name = aim_tlv_getstr(tlvlist, 0x0047, 1); | |
381 | |
382 #if 0 | |
383 if (aim_tlv_gettlv(tlvlist, 0x0049, 1)) { | |
384 /* lastest release serial */ | |
385 } | |
386 #endif | |
387 | |
388 /* | |
389 * URL to change password. | |
390 */ | |
391 if (aim_tlv_gettlv(tlvlist, 0x0054, 1)) | |
392 info->chpassurl = aim_tlv_getstr(tlvlist, 0x0054, 1); | |
393 | |
394 #if 0 | |
395 /* | |
396 * Unknown. Seen on an @mac.com screen name with value of 0x003f | |
397 */ | |
398 if (aim_tlv_gettlv(tlvlist, 0x0055, 1)) { | |
399 /* Unhandled */ | |
400 } | |
401 #endif | |
402 | |
403 od->authinfo = info; | |
404 | |
405 if ((userfunc = aim_callhandler(od, snac ? snac->family : 0x0017, snac ? snac->subtype : 0x0003))) | |
406 ret = userfunc(od, conn, frame, info); | |
407 | |
408 aim_tlvlist_free(&tlvlist); | |
409 | |
410 return ret; | |
411 } | |
412 | |
413 #ifdef USE_XOR_FOR_ICQ | |
414 /* | |
415 * Subtype 0x0007 (kind of) - Send a fake type 0x0007 SNAC to the client | |
416 * | |
417 * This is a bit confusing. | |
418 * | |
419 * Normal SNAC login goes like this: | |
420 * - connect | |
421 * - server sends flap version | |
422 * - client sends flap version | |
423 * - client sends screen name (17/6) | |
424 * - server sends hash key (17/7) | |
425 * - client sends auth request (17/2 -- aim_send_login) | |
426 * - server yells | |
427 * | |
428 * XOR login (for ICQ) goes like this: | |
429 * - connect | |
430 * - server sends flap version | |
431 * - client sends auth request which contains flap version (aim_send_login) | |
432 * - server yells | |
433 * | |
434 * For the client API, we make them implement the most complicated version, | |
435 * and for the simpler version, we fake it and make it look like the more | |
436 * complicated process. | |
437 * | |
438 * This is done by giving the client a faked key, just so we can convince | |
439 * them to call aim_send_login right away, which will detect the session | |
440 * flag that says this is XOR login and ignore the key, sending an ICQ | |
441 * login request instead of the normal SNAC one. | |
442 * | |
443 * As soon as AOL makes ICQ log in the same way as AIM, this is /gone/. | |
444 * | |
445 * XXX This may cause problems if the client relies on callbacks only | |
446 * being called from the context of aim_rxdispatch()... | |
447 * | |
448 */ | |
449 static int | |
450 goddamnicq(OscarData *od, FlapConnection *conn, const char *sn) | |
451 { | |
452 FlapFrame frame; | |
453 aim_rxcallback_t userfunc; | |
454 | |
455 if ((userfunc = aim_callhandler(od, 0x0017, 0x0007))) | |
456 userfunc(od, conn, &frame, ""); | |
457 | |
458 return 0; | |
459 } | |
460 #endif | |
461 | |
462 /* | |
463 * Subtype 0x0006 | |
464 * | |
465 * In AIM 3.5 protocol, the first stage of login is to request login from the | |
466 * Authorizer, passing it the screen name for verification. If the name is | |
467 * invalid, a 0017/0003 is spit back, with the standard error contents. If | |
468 * valid, a 0017/0007 comes back, which is the signal to send it the main | |
469 * login command (0017/0002). | |
470 * | |
471 */ | |
472 int | |
473 aim_request_login(OscarData *od, FlapConnection *conn, const char *sn) | |
474 { | |
475 FlapFrame *frame; | |
476 aim_snacid_t snacid; | |
477 aim_tlvlist_t *tl = NULL; | |
478 | |
479 if (!od || !conn || !sn) | |
480 return -EINVAL; | |
481 | |
482 #ifdef USE_XOR_FOR_ICQ | |
483 if (isdigit(sn[0])) | |
484 return goddamnicq(od, conn, sn); | |
485 #endif | |
486 | |
487 frame = flap_frame_new(od, 0x02, 10+2+2+strlen(sn)+8); | |
488 | |
489 snacid = aim_cachesnac(od, 0x0017, 0x0006, 0x0000, NULL, 0); | |
490 aim_putsnac(&frame->data, 0x0017, 0x0006, 0x0000, snacid); | |
491 | |
492 aim_tlvlist_add_str(&tl, 0x0001, sn); | |
493 | |
494 /* Tell the server we support SecurID logins. */ | |
495 aim_tlvlist_add_noval(&tl, 0x004b); | |
496 | |
497 /* Unknown. Sent in recent WinAIM clients.*/ | |
498 aim_tlvlist_add_noval(&tl, 0x005a); | |
499 | |
500 aim_tlvlist_write(&frame->data, &tl); | |
501 aim_tlvlist_free(&tl); | |
502 | |
503 flap_connection_send(conn, frame); | |
504 | |
505 return 0; | |
506 } | |
507 | |
508 /* | |
509 * Subtype 0x0007 | |
510 * | |
511 * Middle handler for 0017/0007 SNACs. Contains the auth key prefixed | |
512 * by only its length in a two byte word. | |
513 * | |
514 * Calls the client, which should then use the value to call aim_send_login. | |
515 * | |
516 */ | |
517 static int | |
518 keyparse(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) | |
519 { | |
520 int keylen, ret = 1; | |
521 aim_rxcallback_t userfunc; | |
522 char *keystr; | |
523 | |
524 keylen = byte_stream_get16(bs); | |
525 keystr = byte_stream_getstr(bs, keylen); | |
526 | |
527 /* XXX - When GiantGrayPanda signed on AIM I got a thing asking me to register | |
528 * for the netscape network. This SNAC had a type 0x0058 TLV with length 10. | |
529 * Data is 0x0007 0004 3e19 ae1e 0006 0004 0000 0005 */ | |
530 | |
531 if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) | |
532 ret = userfunc(od, conn, frame, keystr); | |
533 | |
534 free(keystr); | |
535 | |
536 return ret; | |
537 } | |
538 | |
539 /** | |
540 * Subtype 0x000a | |
541 * | |
542 * Receive SecurID request. | |
543 */ | |
544 static int | |
545 got_securid_request(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) | |
546 { | |
547 int ret = 0; | |
548 aim_rxcallback_t userfunc; | |
549 | |
550 if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) | |
551 ret = userfunc(od, conn, frame); | |
552 | |
553 return ret; | |
554 } | |
555 | |
556 /** | |
557 * Subtype 0x000b | |
558 * | |
559 * Send SecurID response. | |
560 */ | |
561 int | |
562 aim_auth_securid_send(OscarData *od, const char *securid) | |
563 { | |
564 FlapConnection *conn; | |
565 FlapFrame *frame; | |
566 aim_snacid_t snacid; | |
567 int len; | |
568 | |
569 if (!od || !(conn = flap_connection_getbytype_all(od, SNAC_FAMILY_AUTH)) || !securid) | |
570 return -EINVAL; | |
571 | |
572 len = strlen(securid); | |
573 | |
574 frame = flap_frame_new(od, 0x02, 10+2+len); | |
575 | |
576 snacid = aim_cachesnac(od, SNAC_FAMILY_AUTH, SNAC_SUBTYPE_AUTH_SECURID_RESPONSE, 0x0000, NULL, 0); | |
577 aim_putsnac(&frame->data, SNAC_FAMILY_AUTH, SNAC_SUBTYPE_AUTH_SECURID_RESPONSE, 0x0000, 0); | |
578 | |
579 byte_stream_put16(&frame->data, len); | |
580 byte_stream_putstr(&frame->data, securid); | |
581 | |
582 flap_connection_send(conn, frame); | |
583 | |
584 return 0; | |
585 } | |
586 | |
587 static void | |
588 auth_shutdown(OscarData *od, aim_module_t *mod) | |
589 { | |
590 if (od->authinfo != NULL) | |
591 { | |
592 free(od->authinfo->sn); | |
593 free(od->authinfo->bosip); | |
594 free(od->authinfo->errorurl); | |
595 free(od->authinfo->email); | |
596 free(od->authinfo->chpassurl); | |
597 free(od->authinfo->latestrelease.name); | |
598 free(od->authinfo->latestrelease.url); | |
599 free(od->authinfo->latestrelease.info); | |
600 free(od->authinfo->latestbeta.name); | |
601 free(od->authinfo->latestbeta.url); | |
602 free(od->authinfo->latestbeta.info); | |
603 free(od->authinfo); | |
604 } | |
605 } | |
606 | |
607 static int | |
608 snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) | |
609 { | |
610 if (snac->subtype == 0x0003) | |
611 return parse(od, conn, mod, frame, snac, bs); | |
612 else if (snac->subtype == 0x0007) | |
613 return keyparse(od, conn, mod, frame, snac, bs); | |
614 else if (snac->subtype == 0x000a) | |
615 return got_securid_request(od, conn, mod, frame, snac, bs); | |
616 | |
617 return 0; | |
618 } | |
619 | |
620 int | |
621 auth_modfirst(OscarData *od, aim_module_t *mod) | |
622 { | |
623 mod->family = 0x0017; | |
624 mod->version = 0x0000; | |
625 mod->flags = 0; | |
626 strncpy(mod->name, "auth", sizeof(mod->name)); | |
627 mod->snachandler = snachandler; | |
628 mod->shutdown = auth_shutdown; | |
629 | |
630 return 0; | |
631 } |