Annotation of ChivanetAimPidgin/oscarprpl/src/c/family_auth.c, revision 1.1
1.1 ! snw 1: /*
! 2: * Purple'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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 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 <ctype.h>
! 32:
! 33: #include "cipher.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: 0xf3, 0x26, 0x81, 0xc4,
! 60: 0x39, 0x86, 0xdb, 0x92,
! 61: 0x71, 0xa3, 0xb9, 0xe6,
! 62: 0x53, 0x7a, 0x95, 0x7c
! 63: };
! 64: unsigned int i;
! 65:
! 66: for (i = 0; i < strlen(password); i++)
! 67: encoded[i] = (password[i] ^ encoding_table[i]);
! 68:
! 69: return 0;
! 70: }
! 71: #endif
! 72:
! 73: #ifdef USE_OLD_MD5
! 74: static int
! 75: aim_encode_password_md5(const char *password, size_t password_len, const char *key, guint8 *digest)
! 76: {
! 77: PurpleCipherContext *context;
! 78:
! 79: context = purple_cipher_context_new_by_name("md5", NULL);
! 80: purple_cipher_context_append(context, (const guchar *)key, strlen(key));
! 81: purple_cipher_context_append(context, (const guchar *)password, password_len);
! 82: purple_cipher_context_append(context, (const guchar *)AIM_MD5_STRING, strlen(AIM_MD5_STRING));
! 83: purple_cipher_context_digest(context, 16, digest, NULL);
! 84: purple_cipher_context_destroy(context);
! 85:
! 86: return 0;
! 87: }
! 88: #else
! 89: static int
! 90: aim_encode_password_md5(const char *password, size_t password_len, const char *key, guint8 *digest)
! 91: {
! 92: PurpleCipher *cipher;
! 93: PurpleCipherContext *context;
! 94: guchar passdigest[16];
! 95:
! 96: cipher = purple_ciphers_find_cipher("md5");
! 97:
! 98: context = purple_cipher_context_new(cipher, NULL);
! 99: purple_cipher_context_append(context, (const guchar *)password, password_len);
! 100: purple_cipher_context_digest(context, 16, passdigest, NULL);
! 101: purple_cipher_context_destroy(context);
! 102:
! 103: context = purple_cipher_context_new(cipher, NULL);
! 104: purple_cipher_context_append(context, (const guchar *)key, strlen(key));
! 105: purple_cipher_context_append(context, passdigest, 16);
! 106: purple_cipher_context_append(context, (const guchar *)AIM_MD5_STRING, strlen(AIM_MD5_STRING));
! 107: purple_cipher_context_digest(context, 16, digest, NULL);
! 108: purple_cipher_context_destroy(context);
! 109:
! 110: return 0;
! 111: }
! 112: #endif
! 113:
! 114: #ifdef USE_XOR_FOR_ICQ
! 115: /*
! 116: * Part two of the ICQ hack. Note the ignoring of the key.
! 117: */
! 118: static int
! 119: goddamnicq2(OscarData *od, FlapConnection *conn, const char *sn, const char *password, ClientInfo *ci)
! 120: {
! 121: FlapFrame *frame;
! 122: GSList *tlvlist = NULL;
! 123: int passwdlen;
! 124: guint8 *password_encoded;
! 125: guint32 distrib;
! 126:
! 127: passwdlen = strlen(password);
! 128: password_encoded = (guint8 *)g_malloc(passwdlen+1);
! 129: if (passwdlen > MAXICQPASSLEN)
! 130: passwdlen = MAXICQPASSLEN;
! 131:
! 132: frame = flap_frame_new(od, 0x01, 1152);
! 133:
! 134: aim_encode_password(password, password_encoded);
! 135:
! 136: distrib = oscar_get_ui_info_int(
! 137: od->icq ? "prpl-icq-distid" : "prpl-aim-distid",
! 138: ci->distrib);
! 139:
! 140: byte_stream_put32(&frame->data, 0x00000001); /* FLAP Version */
! 141: aim_tlvlist_add_str(&tlvlist, 0x0001, sn);
! 142: aim_tlvlist_add_raw(&tlvlist, 0x0002, passwdlen, password_encoded);
! 143:
! 144: if (ci->clientstring != NULL)
! 145: aim_tlvlist_add_str(&tlvlist, 0x0003, ci->clientstring);
! 146: else {
! 147: gchar *clientstring = oscar_get_clientstring();
! 148: aim_tlvlist_add_str(&tlvlist, 0x0003, clientstring);
! 149: g_free(clientstring);
! 150: }
! 151: aim_tlvlist_add_16(&tlvlist, 0x0016, (guint16)ci->clientid);
! 152: aim_tlvlist_add_16(&tlvlist, 0x0017, (guint16)ci->major);
! 153: aim_tlvlist_add_16(&tlvlist, 0x0018, (guint16)ci->minor);
! 154: aim_tlvlist_add_16(&tlvlist, 0x0019, (guint16)ci->point);
! 155: aim_tlvlist_add_16(&tlvlist, 0x001a, (guint16)ci->build);
! 156: aim_tlvlist_add_32(&tlvlist, 0x0014, distrib); /* distribution chan */
! 157: aim_tlvlist_add_str(&tlvlist, 0x000f, ci->lang);
! 158: aim_tlvlist_add_str(&tlvlist, 0x000e, ci->country);
! 159:
! 160: aim_tlvlist_write(&frame->data, &tlvlist);
! 161:
! 162: g_free(password_encoded);
! 163: aim_tlvlist_free(tlvlist);
! 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: * @param truncate_pass Truncate the password to 8 characters. This
! 200: * usually happens for AOL accounts. We are told that we
! 201: * should truncate it if the 0x0017/0x0007 SNAC contains
! 202: * a TLV of type 0x0026 with data 0x0000.
! 203: * @param allow_multiple_logins Allow multiple logins? If TRUE, the AIM
! 204: * server will prompt the user when multiple logins occur. If
! 205: * FALSE, existing connections (on other clients) will be
! 206: * disconnected automatically as we connect.
! 207: */
! 208: int
! 209: aim_send_login(OscarData *od, FlapConnection *conn, const char *sn, const char *password, gboolean truncate_pass, ClientInfo *ci, const char *key, gboolean allow_multiple_logins)
! 210: {
! 211: FlapFrame *frame;
! 212: GSList *tlvlist = NULL;
! 213: guint8 digest[16];
! 214: aim_snacid_t snacid;
! 215: size_t password_len;
! 216: guint32 distrib;
! 217:
! 218: if (!ci || !sn || !password)
! 219: return -EINVAL;
! 220:
! 221: #ifdef USE_XOR_FOR_ICQ
! 222: /* If we're signing on an ICQ account then use the older, XOR login method */
! 223: if (aim_snvalid_icq(sn))
! 224: return goddamnicq2(od, conn, sn, password, ci);
! 225: #endif
! 226:
! 227: frame = flap_frame_new(od, 0x02, 1152);
! 228:
! 229: snacid = aim_cachesnac(od, SNAC_FAMILY_AUTH, 0x0002, 0x0000, NULL, 0);
! 230: aim_putsnac(&frame->data, SNAC_FAMILY_AUTH, 0x0002, snacid);
! 231:
! 232: aim_tlvlist_add_str(&tlvlist, 0x0001, sn);
! 233:
! 234: /* Truncate ICQ and AOL passwords, if necessary */
! 235: password_len = strlen(password);
! 236: if (oscar_util_valid_name_icq(sn) && (password_len > MAXICQPASSLEN))
! 237: password_len = MAXICQPASSLEN;
! 238: else if (truncate_pass && password_len > 8)
! 239: password_len = 8;
! 240:
! 241: aim_encode_password_md5(password, password_len, key, digest);
! 242:
! 243: distrib = oscar_get_ui_info_int(
! 244: od->icq ? "prpl-icq-distid" : "prpl-aim-distid",
! 245: ci->distrib);
! 246:
! 247: aim_tlvlist_add_raw(&tlvlist, 0x0025, 16, digest);
! 248:
! 249: #ifndef USE_OLD_MD5
! 250: aim_tlvlist_add_noval(&tlvlist, 0x004c);
! 251: #endif
! 252:
! 253: if (ci->clientstring != NULL)
! 254: aim_tlvlist_add_str(&tlvlist, 0x0003, ci->clientstring);
! 255: else {
! 256: gchar *clientstring = oscar_get_clientstring();
! 257: aim_tlvlist_add_str(&tlvlist, 0x0003, clientstring);
! 258: g_free(clientstring);
! 259: }
! 260: aim_tlvlist_add_16(&tlvlist, 0x0016, (guint16)ci->clientid);
! 261: aim_tlvlist_add_16(&tlvlist, 0x0017, (guint16)ci->major);
! 262: aim_tlvlist_add_16(&tlvlist, 0x0018, (guint16)ci->minor);
! 263: aim_tlvlist_add_16(&tlvlist, 0x0019, (guint16)ci->point);
! 264: aim_tlvlist_add_16(&tlvlist, 0x001a, (guint16)ci->build);
! 265: aim_tlvlist_add_32(&tlvlist, 0x0014, distrib);
! 266: aim_tlvlist_add_str(&tlvlist, 0x000f, ci->lang);
! 267: aim_tlvlist_add_str(&tlvlist, 0x000e, ci->country);
! 268:
! 269: /*
! 270: * If set, old-fashioned buddy lists will not work. You will need
! 271: * to use SSI.
! 272: */
! 273: aim_tlvlist_add_8(&tlvlist, 0x004a, (allow_multiple_logins ? 0x01 : 0x03));
! 274:
! 275: aim_tlvlist_write(&frame->data, &tlvlist);
! 276:
! 277: aim_tlvlist_free(tlvlist);
! 278:
! 279: flap_connection_send(conn, frame);
! 280:
! 281: return 0;
! 282: }
! 283:
! 284: /*
! 285: * This is sent back as a general response to the login command.
! 286: * It can be either an error or a success, depending on the
! 287: * presence of certain TLVs.
! 288: *
! 289: * The client should check the value passed as errorcode. If
! 290: * its nonzero, there was an error.
! 291: */
! 292: static int
! 293: parse(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
! 294: {
! 295: GSList *tlvlist;
! 296: aim_rxcallback_t userfunc;
! 297: struct aim_authresp_info *info;
! 298: int ret = 0;
! 299:
! 300: info = g_new0(struct aim_authresp_info, 1);
! 301:
! 302: /*
! 303: * Read block of TLVs. All further data is derived
! 304: * from what is parsed here.
! 305: */
! 306: tlvlist = aim_tlvlist_read(bs);
! 307:
! 308: /*
! 309: * No matter what, we should have a username.
! 310: */
! 311: if (aim_tlv_gettlv(tlvlist, 0x0001, 1)) {
! 312: info->bn = aim_tlv_getstr(tlvlist, 0x0001, 1);
! 313: purple_connection_set_display_name(od->gc, info->bn);
! 314: }
! 315:
! 316: /*
! 317: * Check for an error code. If so, we should also
! 318: * have an error url.
! 319: */
! 320: if (aim_tlv_gettlv(tlvlist, 0x0008, 1))
! 321: info->errorcode = aim_tlv_get16(tlvlist, 0x0008, 1);
! 322: if (aim_tlv_gettlv(tlvlist, 0x0004, 1))
! 323: info->errorurl = aim_tlv_getstr(tlvlist, 0x0004, 1);
! 324:
! 325: /*
! 326: * BOS server address.
! 327: */
! 328: if (aim_tlv_gettlv(tlvlist, 0x0005, 1))
! 329: info->bosip = aim_tlv_getstr(tlvlist, 0x0005, 1);
! 330:
! 331: /*
! 332: * Authorization cookie.
! 333: */
! 334: if (aim_tlv_gettlv(tlvlist, 0x0006, 1)) {
! 335: aim_tlv_t *tmptlv;
! 336:
! 337: tmptlv = aim_tlv_gettlv(tlvlist, 0x0006, 1);
! 338: if (tmptlv != NULL)
! 339: {
! 340: info->cookielen = tmptlv->length;
! 341: info->cookie = tmptlv->value;
! 342: }
! 343: }
! 344:
! 345: /*
! 346: * The email address attached to this account
! 347: * Not available for ICQ or @mac.com logins.
! 348: * If you receive this TLV, then you are allowed to use
! 349: * family 0x0018 to check the status of your email.
! 350: * XXX - Not really true!
! 351: */
! 352: if (aim_tlv_gettlv(tlvlist, 0x0011, 1))
! 353: info->email = aim_tlv_getstr(tlvlist, 0x0011, 1);
! 354:
! 355: /*
! 356: * The registration status. (Not real sure what it means.)
! 357: * Not available for ICQ or @mac.com logins.
! 358: *
! 359: * 1 = No disclosure
! 360: * 2 = Limited disclosure
! 361: * 3 = Full disclosure
! 362: *
! 363: * This has to do with whether your email address is available
! 364: * to other users or not. AFAIK, this feature is no longer used.
! 365: *
! 366: * Means you can use the admin family? (0x0007)
! 367: *
! 368: */
! 369: if (aim_tlv_gettlv(tlvlist, 0x0013, 1))
! 370: info->regstatus = aim_tlv_get16(tlvlist, 0x0013, 1);
! 371:
! 372: if (aim_tlv_gettlv(tlvlist, 0x0040, 1))
! 373: info->latestbeta.build = aim_tlv_get32(tlvlist, 0x0040, 1);
! 374: if (aim_tlv_gettlv(tlvlist, 0x0041, 1))
! 375: info->latestbeta.url = aim_tlv_getstr(tlvlist, 0x0041, 1);
! 376: if (aim_tlv_gettlv(tlvlist, 0x0042, 1))
! 377: info->latestbeta.info = aim_tlv_getstr(tlvlist, 0x0042, 1);
! 378: if (aim_tlv_gettlv(tlvlist, 0x0043, 1))
! 379: info->latestbeta.name = aim_tlv_getstr(tlvlist, 0x0043, 1);
! 380:
! 381: if (aim_tlv_gettlv(tlvlist, 0x0044, 1))
! 382: info->latestrelease.build = aim_tlv_get32(tlvlist, 0x0044, 1);
! 383: if (aim_tlv_gettlv(tlvlist, 0x0045, 1))
! 384: info->latestrelease.url = aim_tlv_getstr(tlvlist, 0x0045, 1);
! 385: if (aim_tlv_gettlv(tlvlist, 0x0046, 1))
! 386: info->latestrelease.info = aim_tlv_getstr(tlvlist, 0x0046, 1);
! 387: if (aim_tlv_gettlv(tlvlist, 0x0047, 1))
! 388: info->latestrelease.name = aim_tlv_getstr(tlvlist, 0x0047, 1);
! 389:
! 390: /*
! 391: * URL to change password.
! 392: */
! 393: if (aim_tlv_gettlv(tlvlist, 0x0054, 1))
! 394: info->chpassurl = aim_tlv_getstr(tlvlist, 0x0054, 1);
! 395:
! 396: od->authinfo = info;
! 397:
! 398: if ((userfunc = aim_callhandler(od, snac ? snac->family : SNAC_FAMILY_AUTH, snac ? snac->subtype : 0x0003)))
! 399: ret = userfunc(od, conn, frame, info);
! 400:
! 401: aim_tlvlist_free(tlvlist);
! 402:
! 403: return ret;
! 404: }
! 405:
! 406: #ifdef USE_XOR_FOR_ICQ
! 407: /*
! 408: * Subtype 0x0007 (kind of) - Send a fake type 0x0007 SNAC to the client
! 409: *
! 410: * This is a bit confusing.
! 411: *
! 412: * Normal SNAC login goes like this:
! 413: * - connect
! 414: * - server sends flap version
! 415: * - client sends flap version
! 416: * - client sends username (17/6)
! 417: * - server sends hash key (17/7)
! 418: * - client sends auth request (17/2 -- aim_send_login)
! 419: * - server yells
! 420: *
! 421: * XOR login (for ICQ) goes like this:
! 422: * - connect
! 423: * - server sends flap version
! 424: * - client sends auth request which contains flap version (aim_send_login)
! 425: * - server yells
! 426: *
! 427: * For the client API, we make them implement the most complicated version,
! 428: * and for the simpler version, we fake it and make it look like the more
! 429: * complicated process.
! 430: *
! 431: * This is done by giving the client a faked key, just so we can convince
! 432: * them to call aim_send_login right away, which will detect the session
! 433: * flag that says this is XOR login and ignore the key, sending an ICQ
! 434: * login request instead of the normal SNAC one.
! 435: *
! 436: * As soon as AOL makes ICQ log in the same way as AIM, this is /gone/.
! 437: */
! 438: static int
! 439: goddamnicq(OscarData *od, FlapConnection *conn, const char *sn)
! 440: {
! 441: FlapFrame frame;
! 442: aim_rxcallback_t userfunc;
! 443:
! 444: if ((userfunc = aim_callhandler(od, SNAC_FAMILY_AUTH, 0x0007)))
! 445: userfunc(od, conn, &frame, "");
! 446:
! 447: return 0;
! 448: }
! 449: #endif
! 450:
! 451: /*
! 452: * Subtype 0x0006
! 453: *
! 454: * In AIM 3.5 protocol, the first stage of login is to request login from the
! 455: * Authorizer, passing it the username for verification. If the name is
! 456: * invalid, a 0017/0003 is spit back, with the standard error contents. If
! 457: * valid, a 0017/0007 comes back, which is the signal to send it the main
! 458: * login command (0017/0002).
! 459: *
! 460: */
! 461: int
! 462: aim_request_login(OscarData *od, FlapConnection *conn, const char *sn)
! 463: {
! 464: FlapFrame *frame;
! 465: aim_snacid_t snacid;
! 466: GSList *tlvlist = NULL;
! 467:
! 468: if (!od || !conn || !sn)
! 469: return -EINVAL;
! 470:
! 471: #ifdef USE_XOR_FOR_ICQ
! 472: if (aim_snvalid_icq(sn))
! 473: return goddamnicq(od, conn, sn);
! 474: #endif
! 475:
! 476: frame = flap_frame_new(od, 0x02, 10+2+2+strlen(sn)+8);
! 477:
! 478: snacid = aim_cachesnac(od, SNAC_FAMILY_AUTH, 0x0006, 0x0000, NULL, 0);
! 479: aim_putsnac(&frame->data, SNAC_FAMILY_AUTH, 0x0006, snacid);
! 480:
! 481: aim_tlvlist_add_str(&tlvlist, 0x0001, sn);
! 482:
! 483: /* Tell the server we support SecurID logins. */
! 484: aim_tlvlist_add_noval(&tlvlist, 0x004b);
! 485:
! 486: /* Unknown. Sent in recent WinAIM clients.*/
! 487: aim_tlvlist_add_noval(&tlvlist, 0x005a);
! 488:
! 489: aim_tlvlist_write(&frame->data, &tlvlist);
! 490: aim_tlvlist_free(tlvlist);
! 491:
! 492: flap_connection_send(conn, frame);
! 493:
! 494: return 0;
! 495: }
! 496:
! 497: /*
! 498: * Subtype 0x0007
! 499: *
! 500: * Middle handler for 0017/0007 SNACs. Contains the auth key prefixed
! 501: * by only its length in a two byte word.
! 502: *
! 503: * Calls the client, which should then use the value to call aim_send_login.
! 504: *
! 505: */
! 506: static int
! 507: keyparse(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
! 508: {
! 509: int keylen, ret = 1;
! 510: aim_rxcallback_t userfunc;
! 511: char *keystr;
! 512: GSList *tlvlist;
! 513: gboolean truncate_pass;
! 514:
! 515: keylen = byte_stream_get16(bs);
! 516: keystr = byte_stream_getstr(bs, keylen);
! 517: tlvlist = aim_tlvlist_read(bs);
! 518:
! 519: /*
! 520: * If the truncate_pass TLV exists then we should truncate the
! 521: * user's password to 8 characters. This flag is sent to us
! 522: * when logging in with an AOL user's username.
! 523: */
! 524: truncate_pass = aim_tlv_gettlv(tlvlist, 0x0026, 1) != NULL;
! 525:
! 526: /* XXX - When GiantGrayPanda signed on AIM I got a thing asking me to register
! 527: * for the netscape network. This SNAC had a type 0x0058 TLV with length 10.
! 528: * Data is 0x0007 0004 3e19 ae1e 0006 0004 0000 0005 */
! 529:
! 530: if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
! 531: ret = userfunc(od, conn, frame, keystr, (int)truncate_pass);
! 532:
! 533: g_free(keystr);
! 534: aim_tlvlist_free(tlvlist);
! 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: int len;
! 567:
! 568: if (!od || !(conn = flap_connection_getbytype_all(od, SNAC_FAMILY_AUTH)) || !securid)
! 569: return -EINVAL;
! 570:
! 571: len = strlen(securid);
! 572:
! 573: frame = flap_frame_new(od, 0x02, 10+2+len);
! 574:
! 575: /* aim_snacid_t snacid = */ aim_cachesnac(od, SNAC_FAMILY_AUTH, SNAC_SUBTYPE_AUTH_SECURID_RESPONSE, 0x0000, NULL, 0);
! 576: aim_putsnac(&frame->data, SNAC_FAMILY_AUTH, SNAC_SUBTYPE_AUTH_SECURID_RESPONSE, 0);
! 577:
! 578: byte_stream_put16(&frame->data, len);
! 579: byte_stream_putstr(&frame->data, securid);
! 580:
! 581: flap_connection_send(conn, frame);
! 582:
! 583: return 0;
! 584: }
! 585:
! 586: static void
! 587: auth_shutdown(OscarData *od, aim_module_t *mod)
! 588: {
! 589: if (od->authinfo != NULL)
! 590: {
! 591: g_free(od->authinfo->bn);
! 592: g_free(od->authinfo->bosip);
! 593: g_free(od->authinfo->errorurl);
! 594: g_free(od->authinfo->email);
! 595: g_free(od->authinfo->chpassurl);
! 596: g_free(od->authinfo->latestrelease.name);
! 597: g_free(od->authinfo->latestrelease.url);
! 598: g_free(od->authinfo->latestrelease.info);
! 599: g_free(od->authinfo->latestbeta.name);
! 600: g_free(od->authinfo->latestbeta.url);
! 601: g_free(od->authinfo->latestbeta.info);
! 602: g_free(od->authinfo);
! 603: }
! 604: }
! 605:
! 606: static int
! 607: snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
! 608: {
! 609: if (snac->subtype == 0x0003)
! 610: return parse(od, conn, mod, frame, snac, bs);
! 611: else if (snac->subtype == 0x0007)
! 612: return keyparse(od, conn, mod, frame, snac, bs);
! 613: else if (snac->subtype == 0x000a)
! 614: return got_securid_request(od, conn, mod, frame, snac, bs);
! 615:
! 616: return 0;
! 617: }
! 618:
! 619: int
! 620: auth_modfirst(OscarData *od, aim_module_t *mod)
! 621: {
! 622: mod->family = SNAC_FAMILY_AUTH;
! 623: mod->version = 0x0000;
! 624: mod->flags = 0;
! 625: strncpy(mod->name, "auth", sizeof(mod->name));
! 626: mod->snachandler = snachandler;
! 627: mod->shutdown = auth_shutdown;
! 628:
! 629: return 0;
! 630: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>