Annotation of ChivanetAimPidgin/oscarprpl/src/c/family_auth.c, revision 1.1.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>