From 01b59e1e19a0f8bbde04b559038984cfb438d4f8 Mon Sep 17 00:00:00 2001 From: mid Date: Wed, 29 Dec 1999 04:22:21 +0000 Subject: [PATCH] Lots of minor cleanups. Adds new (disabled) SNAC-based login. --- CHANGES | 13 ++ Makefile.rules | 2 +- aim_login.c | 201 +++++++++++++++++- aim_misc.c | 108 +++++++++- aim_rxhandlers.c | 418 ++++++++++++++++++++++---------------- aim_tlv.c | 23 +++ faim/aim.h | 7 + faim/aim_cbtypes.h | 13 ++ faim/faimconfig.h | 24 ++- utils/faimtest/faimtest.c | 83 ++++++-- 10 files changed, 683 insertions(+), 209 deletions(-) diff --git a/CHANGES b/CHANGES index 5f1f7b0..d7e4891 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,19 @@ No release numbers ------------------ + - Wed Dec 29 04:17:03 UTC 1999 + - Added -g to CFLAGS + - Added aim_sendconnack() to aim_login.c (needed for newer login) + - Added code for the new SNAC-based login/auth procedure. (see SNACLOGIN + in faim/faimconfig.h for why its not enabled) + - Reimplemented aim_authparse(), aim_handleredirect() using TLVlists + - The old auth_failed callback is now integrated into the + success one. If there was an error, logininfo->errorcode is nonzero + - Fiddled with version information. Added aim_setversions() + - Added table of SNAC names for showing unknown snacs (jbm) + - Added a middle handler for MOTD + - Added new authorization SNACs to faim/aim_cbtypes.h + - Sun Dec 26 22:59:10 UTC 1999 - Renamed login_phase1_struct to aim_login_struct - Changed cookie and sn to be static arrays in aim_login_struct diff --git a/Makefile.rules b/Makefile.rules index 69f18a6..a34f70e 100644 --- a/Makefile.rules +++ b/Makefile.rules @@ -1,5 +1,5 @@ -CFLAGS = -Wstrict-prototypes -Wall -I. +CFLAGS = -Wstrict-prototypes -Wall -I. -g ifdef LIBFAIM_INC CFLAGS += -I$(LIBFAIM_INC) diff --git a/aim_login.c b/aim_login.c index c7af989..61992a1 100644 --- a/aim_login.c +++ b/aim_login.c @@ -15,6 +15,69 @@ #include "tis_telnet_proxy.h" #endif +int aim_sendconnack(struct aim_session_t *sess, + struct aim_conn_t *conn) +{ + int curbyte=0; + + struct command_tx_struct newpacket; + + if (conn) + newpacket.conn = conn; + else + return -1; + + newpacket.commandlen = 2+2; + newpacket.data = (u_char *) calloc (1, newpacket.commandlen ); + newpacket.lock = 1; + newpacket.type = 0x01; + + curbyte += aimutil_put16(newpacket.data+curbyte, 0x0000); + curbyte += aimutil_put16(newpacket.data+curbyte, 0x0001); + + newpacket.lock = 0; + aim_tx_enqueue(sess, &newpacket); + + return 0; +} + +#ifdef SNACLOGIN +/* + * In AIM 3.5 protocol, the first stage of login is to request + * login from the Authorizer, passing it the screen name + * for verification. If the name is invalid, a 0017/0003 + * is spit back, with the standard error contents. If valid, + * a 0017/0007 comes back, which is the signal to send + * it the main login command (0017/0002). + */ +int aim_request_login(struct aim_session_t *sess, + struct aim_conn_t *conn, + char *sn) +{ + int curbyte=0; + + struct command_tx_struct newpacket; + + if (conn) + newpacket.conn = conn; + else + newpacket.conn = aim_getconn_type(sess, AIM_CONN_TYPE_AUTH); + + newpacket.commandlen = 10+2+2+strlen(sn); + newpacket.data = (u_char *) calloc (1, newpacket.commandlen ); + newpacket.lock = 1; + newpacket.type = 0x02; + + curbyte += aim_putsnac(newpacket.data+curbyte, 0x0017, 0x0006, 0x0000, 0x00010000); + curbyte += aim_puttlv_str(newpacket.data+curbyte, 0x0001, strlen(sn), sn); + + newpacket.lock = 0; + aim_tx_enqueue(sess, &newpacket); + + return 0; +} +#endif /* SNACLOGIN */ + /* * send_login(int socket, char *sn, char *password) * @@ -34,18 +97,52 @@ int aim_send_login (struct aim_session_t *sess, struct command_tx_struct newpacket; + if (!clientinfo || !sn || !password) + return -1; + if (conn) newpacket.conn = conn; else newpacket.conn = aim_getconn_type(sess, AIM_CONN_TYPE_AUTH); +#ifdef SNACLOGIN + newpacket.commandlen = 10; + newpacket.commandlen += 2 + 2 + strlen(sn); + newpacket.commandlen += 2 + 2 + strlen(password); + newpacket.commandlen += 2 + 2 + strlen(clientinfo->clientstring); + newpacket.commandlen += 56; + + newpacket.data = (u_char *) calloc (1, newpacket.commandlen ); + newpacket.lock = 1; + newpacket.type = 0x02; + + curbyte = aim_putsnac(newpacket.data+curbyte, 0x0017, 0x0002, 0x0000, 0x00010000); + curbyte+= aim_puttlv_str(newpacket.data+curbyte, 0x0001, strlen(sn), sn); + password_encoded = (u_char *) malloc(strlen(password)); + aim_encode_password(password, password_encoded); + curbyte+= aim_puttlv_str(newpacket.data+curbyte, 0x0002, strlen(password), password_encoded); + curbyte+= aim_puttlv_str(newpacket.data+curbyte, 0x0003, + strlen(clientinfo->clientstring), + clientinfo->clientstring); + /* XXX: should use clientinfo provided version info */ + curbyte+= aim_puttlv_16(newpacket.data+curbyte, 0x0016, 0x0004); + curbyte+= aim_puttlv_16(newpacket.data+curbyte, 0x0017, 0x0003); + curbyte+= aim_puttlv_16(newpacket.data+curbyte, 0x0018, 0x0005); + curbyte+= aim_puttlv_16(newpacket.data+curbyte, 0x0019, 0x0000); + curbyte+= aim_puttlv_16(newpacket.data+curbyte, 0x001a, 0x0686); + curbyte+= aim_puttlv_str(newpacket.data+curbyte, 0x0001, 0x0002, clientinfo->country); + curbyte+= aim_puttlv_str(newpacket.data+curbyte, 0x0001, 0x0002, clientinfo->lang); + curbyte+= aim_puttlv_32(newpacket.data+curbyte, 0x0014, 0x0000002a); + curbyte+= aim_puttlv_16(newpacket.data+curbyte, 0x0009, 0x0015); +#else + newpacket.commandlen = 4 + 4+strlen(sn) + 4+strlen(password) + 6; if (clientinfo) { if (strlen(clientinfo->clientstring)) newpacket.commandlen += 4+strlen(clientinfo->clientstring); - newpacket.commandlen += 6+6+6; + newpacket.commandlen += 6+6+6+6; if (strlen(clientinfo->country)) newpacket.commandlen += 4+strlen(clientinfo->country); if (strlen(clientinfo->lang)) @@ -70,7 +167,7 @@ int aim_send_login (struct aim_session_t *sess, curbyte += aimutil_putstr(newpacket.data+curbyte, password_encoded, strlen(password)); free(password_encoded); - curbyte += aim_puttlv_16(newpacket.data+curbyte, 0x0016, 0x0001); + curbyte += aim_puttlv_16(newpacket.data+curbyte, 0x0016, 0x0004); if (clientinfo) { @@ -80,9 +177,10 @@ int aim_send_login (struct aim_session_t *sess, curbyte += aimutil_put16(newpacket.data+curbyte, strlen(clientinfo->clientstring)); curbyte += aimutil_putstr(newpacket.data+curbyte, clientinfo->clientstring, strlen(clientinfo->clientstring)); } - curbyte += aim_puttlv_16(newpacket.data+curbyte, 0x0017, 0x0001); - curbyte += aim_puttlv_16(newpacket.data+curbyte, 0x0018, 0x0001); - curbyte += aim_puttlv_16(newpacket.data+curbyte, 0x001a, 0x0013); + curbyte += aim_puttlv_16(newpacket.data+curbyte, 0x0017, clientinfo->major /*0x0001*/); + curbyte += aim_puttlv_16(newpacket.data+curbyte, 0x0018, clientinfo->minor /*0x0001*/); + curbyte += aim_puttlv_16(newpacket.data+curbyte, 0x0019, 0x0000); + curbyte += aim_puttlv_16(newpacket.data+curbyte, 0x001a, clientinfo->build /*0x0013*/); if (strlen(clientinfo->country)) { curbyte += aimutil_put16(newpacket.data+curbyte, 0x000e); @@ -98,6 +196,7 @@ int aim_send_login (struct aim_session_t *sess, } curbyte += aim_puttlv_16(newpacket.data+curbyte, 0x0009, 0x0015); +#endif newpacket.lock = 0; aim_tx_enqueue(sess, &newpacket); @@ -138,6 +237,98 @@ int aim_encode_password(const char *password, u_char *encoded) return 0; } +/* + * This is sent back as a general response to the login command. + * It can be either an error or a success, depending on the + * precense of certain TLVs. + * + * The client should check the value of logininfo->errorcode. If + * its nonzero, there was an error. + * + */ +int aim_authparse(struct aim_session_t *sess, + struct command_rx_struct *command) +{ + struct aim_tlvlist_t *tlvlist; + int ret = 1; + char *sn; + rxcallback_t userfunc = NULL; + + memset(&sess->logininfo, 0x00, sizeof(sess->logininfo)); + + /* + * Read block of TLVs. All further data is derived + * from what is parsed here. + */ +#ifdef SNACLOGIN + tlvlist = aim_readtlvchain(command->data+10, command->commandlen-10); +#else + tlvlist = aim_readtlvchain(command->data, command->commandlen); +#endif + /* + * No matter what, we should have a screen name. + */ + sn = aim_gettlv_str(tlvlist, 0x0001, 1); + memcpy(sess->logininfo.screen_name, sn, strlen(sn)); + sn[(strlen(sn))] = '\0'; + + /* + * Check for an error code. If so, we should also + * have an error url. + */ + if (aim_gettlv(tlvlist, 0x0008, 1)) + { + struct aim_tlv_t *errtlv; + errtlv = aim_gettlv(tlvlist, 0x0008, 1); + sess->logininfo.errorcode = aimutil_get16(errtlv->value); + sess->logininfo.errorurl = aim_gettlv_str(tlvlist, 0x0004, 1); + } + /* + * If we have both an IP number (0x0005) and a cookie (0x0006), + * then the login was successful. + */ + else if (aim_gettlv(tlvlist, 0x0005, 1) && aim_gettlv(tlvlist, 0x0006, 1)) + { + struct aim_tlv_t *tmptlv; + /* + * IP address of BOS server. + */ + sess->logininfo.BOSIP = aim_gettlv_str(tlvlist, 0x0005, 1); + /* + * Authorization Cookie + */ + tmptlv = aim_gettlv(tlvlist, 0x0006, 1); + memcpy(sess->logininfo.cookie, tmptlv->value, AIM_COOKIELEN); + /* + * The email address attached to this account + */ + sess->logininfo.email = aim_gettlv_str(tlvlist, 0x0011, 1); + + /* + * The registration status. (Not real sure what it means.) + */ + tmptlv = aim_gettlv(tlvlist, 0x0013, 1); + sess->logininfo.regstatus = aimutil_get16(tmptlv->value); + + } + +#ifdef SNACLOGIN + userfunc = aim_callhandler(command->conn, 0x0017, 0x0003); +#else + userfunc = aim_callhandler(command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_AUTHSUCCESS); +#endif + if (userfunc) + ret = userfunc(sess, command); + + aim_freetlvchain(&tlvlist); + + /* These have been clobbered by the freetlvchain */ + sess->logininfo.BOSIP = NULL; + sess->logininfo.email = NULL; + sess->logininfo.errorurl = NULL; + + return ret; +} diff --git a/aim_misc.c b/aim_misc.c index f53d5b6..dae9e9e 100644 --- a/aim_misc.c +++ b/aim_misc.c @@ -309,15 +309,45 @@ u_long aim_bos_clientready(struct aim_session_t *sess, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* real data */ - 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, - 0x00, 0x13, 0x00, 0x09, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x0b, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x01, + 0x00, 0x03, + 0x00, 0x04, + 0x06, 0x86, + 0x00, 0x02, + 0x00, 0x01, + 0x00, 0x04, + 0x00, 0x01, + + 0x00, 0x03, + 0x00, 0x01, + 0x00, 0x04, + 0x00, 0x01, + 0x00, 0x04, + 0x00, 0x01, + 0x00, 0x04, + 0x00, 0x01, + + 0x00, 0x06, + 0x00, 0x01, + 0x00, 0x04, + 0x00, 0x01, + 0x00, 0x08, + 0x00, 0x01, + 0x00, 0x04, + 0x00, 0x01, + + 0x00, 0x09, + 0x00, 0x01, + 0x00, 0x04, + 0x00, 0x01, + 0x00, 0x0a, + 0x00, 0x01, + 0x00, 0x04, + 0x00, 0x01, + + 0x00, 0x0b, + 0x00, 0x01, + 0x00, 0x04, 0x00, 0x01 }; int command_2_len = 0x52; @@ -433,11 +463,71 @@ u_long aim_bos_reqpersonalinfo(struct aim_session_t *sess, newpacket.data[10] = 0x0d; newpacket.data[11] = 0xda; + newpacket.lock = 0; aim_tx_enqueue(sess, &newpacket); return (sess->snac_nextid++); } +u_long aim_setversions(struct aim_session_t *sess, + struct aim_conn_t *conn) +{ + struct command_tx_struct newpacket; + int i,j; + + newpacket.lock = 1; + if (conn) + newpacket.conn = conn; + else + newpacket.conn = aim_getconn_type(sess, AIM_CONN_TYPE_BOS); + newpacket.type = 0x02; + newpacket.commandlen = 10 + (4*13); + + newpacket.data = (char *) malloc(newpacket.commandlen); + i = aim_putsnac(newpacket.data, 0x0001, 0x0017, 0x0000, sess->snac_nextid); + + i += aimutil_put16(newpacket.data+i, 0x0001); + i += aimutil_put16(newpacket.data+i, 0x0003); + i += aimutil_put16(newpacket.data+i, 0x0002); + i += aimutil_put16(newpacket.data+i, 0x0001); + i += aimutil_put16(newpacket.data+i, 0x0003); + i += aimutil_put16(newpacket.data+i, 0x0001); + i += aimutil_put16(newpacket.data+i, 0x0004); + i += aimutil_put16(newpacket.data+i, 0x0001); + i += aimutil_put16(newpacket.data+i, 0x0006); + i += aimutil_put16(newpacket.data+i, 0x0001); + i += aimutil_put16(newpacket.data+i, 0x0008); + i += aimutil_put16(newpacket.data+i, 0x0001); + i += aimutil_put16(newpacket.data+i, 0x0009); + i += aimutil_put16(newpacket.data+i, 0x0001); + i += aimutil_put16(newpacket.data+i, 0x000a); + i += aimutil_put16(newpacket.data+i, 0x0001); + i += aimutil_put16(newpacket.data+i, 0x000b); + i += aimutil_put16(newpacket.data+i, 0x0002); + i += aimutil_put16(newpacket.data+i, 0x000c); + i += aimutil_put16(newpacket.data+i, 0x0001); + i += aimutil_put16(newpacket.data+i, 0x0015); + i += aimutil_put16(newpacket.data+i, 0x0003); + i += aimutil_put16(newpacket.data+i, 0x000f); + i += aimutil_put16(newpacket.data+i, 0x0001); + i += aimutil_put16(newpacket.data+i, 0x0005); + i += aimutil_put16(newpacket.data+i, 0x0001); + +#if 0 + for (j = 0; j < 0x10; j++) +A + { + i += aimutil_put16(newpacket.data+i, j); /* family */ + i += aimutil_put16(newpacket.data+i, 0x0003); /* version */ + } +#endif + newpacket.lock = 0; + aim_tx_enqueue(sess, &newpacket); + + return (sess->snac_nextid++); +} + + /* * aim_bos_reqservice(serviceid) * diff --git a/aim_rxhandlers.c b/aim_rxhandlers.c index d6bdc98..3e81c92 100644 --- a/aim_rxhandlers.c +++ b/aim_rxhandlers.c @@ -17,9 +17,167 @@ int bleck(struct aim_session_t *sess,struct command_rx_struct *workingPtr, ...) { u_short family; u_short subtype; - family = (workingPtr->data[0] << 8) + workingPtr->data[1]; - subtype = (workingPtr->data[2] << 8) + workingPtr->data[3]; - printf("bleck: null handler for %04x/%04x\n", family, subtype); + + u_short maxf; + u_short maxs; + + /* XXX: this is ugly. and big just for debugging. */ + char *literals[14][25] = { + {"Invalid", + NULL + }, + {"General", + "Invalid", + "Error", + "Client Ready", + "Server Ready", + "Service Request", + "Redirect", + "Rate Information Request", + "Rate Information", + "Rate Information Ack", + NULL, + "Rate Information Change", + "Server Pause", + NULL, + "Server Resume", + "Request Personal User Information", + "Personal User Information", + "Evil Notification", + NULL, + "Migration notice", + "Message of the Day", + "Set Privacy Flags", + "Well Known URL", + "NOP" + }, + {"Location", + "Invalid", + "Error", + "Request Rights", + "Rights Information", + "Set user information", + "Request User Information", + "User Information", + "Watcher Sub Request", + "Watcher Notification" + }, + {"Buddy List Management", + "Invalid", + "Error", + "Request Rights", + "Rights Information", + "Add Buddy", + "Remove Buddy", + "Watcher List Query", + "Watcher List Response", + "Watcher SubRequest", + "Watcher Notification", + "Reject Notification", + "Oncoming Buddy", + "Offgoing Buddy" + }, + {"Messeging", + "Invalid", + "Error", + "Add ICBM Parameter", + "Remove ICBM Parameter", + "Request Parameter Information", + "Parameter Information", + "Outgoing Message", + "Incoming Message", + "Evil Request", + "Evil Reply", + "Missed Calls", + "Message Error", + "Host Ack" + }, + {"Advertisements", + "Invalid", + "Error", + "Request Ad", + "Ad Data (GIFs)" + }, + {"Invitation / Client-to-Client", + "Invalid", + "Error", + "Invite a Friend", + "Invitation Ack" + }, + {"Administrative", + "Invalid", + "Error", + "Information Request", + "Information Reply", + "Information Change Request", + "Information Chat Reply", + "Account Confirm Request", + "Account Confirm Reply", + "Account Delete Request", + "Account Delete Reply" + }, + {"Popups", + "Invalid", + "Error", + "Display Popup" + }, + {"BOS", + "Invalid", + "Error", + "Request Rights", + "Rights Response", + "Set group permission mask", + "Add permission list entries", + "Delete permission list entries", + "Add deny list entries", + "Delete deny list entries", + "Server Error" + }, + {"User Lookup", + "Invalid", + "Error", + "Search Request", + "Search Response" + }, + {"Stats", + "Invalid", + "Error", + "Set minimum report interval", + "Report Events" + }, + {"Translate", + "Invalid", + "Error", + "Translate Request", + "Translate Reply", + }, + {"Chat Navigation", + "Invalid", + "Error", + "Request rights", + "Request Exchange Information", + "Request Room Information", + "Request Occupant List", + "Search for Room", + "Outgoing Message", + "Incoming Message", + "Evil Request", + "Evil Reply", + "Chat Error", + } + }; + + maxf = sizeof(literals) / sizeof(literals[0]); + maxs = sizeof(literals[0]) / sizeof(literals[0][0]); + + family = aimutil_get16(workingPtr->data+0); + subtype= aimutil_get16(workingPtr->data+2); + + if((family < maxf) && (subtype+1 < maxs) && (literals[family][subtype] != NULL)) + printf("bleck: null handler for %04x/%04x (%s)\n", family, subtype, literals[family][subtype+1]); + else + printf("bleck: null handler for %04x/%04x (no literal)\n",family,subtype); + return 1; } @@ -169,8 +327,43 @@ int aim_rxdispatch(struct aim_session_t *sess) } else { - /* any user callbacks will be called from here */ - workingPtr->handled = aim_authparse(sess, workingPtr); + u_short family,subtype; + + family = aimutil_get16(workingPtr->data); + subtype = aimutil_get16(workingPtr->data+2); + + switch (family) + { + /* New login protocol */ +#ifdef SNACLOGIN + case 0x0017: + if (subtype == 0x0001) + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0x0001, workingPtr); + else if (subtype == 0x0003) + workingPtr->handled = aim_authparse(sess, workingPtr); + else if (subtype == 0x0007) + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0x0007, workingPtr); + else + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0017, 0xffff, workingPtr); + break; +#else + /* XXX: this isnt foolproof */ + case 0x0001: + if (subtype == 0x0003) + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY, workingPtr); + else + workingPtr->handled = aim_authparse(sess, workingPtr); + break; + case 0x0007: + if (subtype == 0x0005) + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_ADM, AIM_CB_ADM_INFOCHANGE_REPLY, workingPtr); + break; + default: + /* Old login protocol */ + /* any user callbacks will be called from here */ + workingPtr->handled = aim_authparse(sess, workingPtr); +#endif + } } } break; @@ -212,7 +405,7 @@ int aim_rxdispatch(struct aim_session_t *sess) workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x000f, workingPtr); break; case 0x0013: - workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0001, 0x0013, workingPtr); + workingPtr->handled = aim_parsemotd_middle(sess, workingPtr); break; default: workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_DEFAULT, workingPtr); @@ -344,192 +537,65 @@ int aim_rxdispatch(struct aim_session_t *sess) return 0; } -/* - * TODO: check and cure memory leakage in this function. - * TODO: update to use new tlvlist routines - */ -int aim_authparse(struct aim_session_t *sess, - struct command_rx_struct *command) +int aim_parsemotd_middle(struct aim_session_t *sess, + struct command_rx_struct *command, ...) { rxcallback_t userfunc = NULL; - int iserror = 0; - struct aim_tlv_t *tlv = NULL; - char *errorurl = NULL; - short errorcode = 0x00; - u_int z = 0; - u_short family,subtype; - - family = aimutil_get16(command->data); - subtype= aimutil_get16(command->data+2); + char *msg; + int ret=1; + struct aim_tlvlist_t *tlvlist; + u_short id; + + /* + * Dunno. + */ + id = aimutil_get16(command->data+10); + + /* + * TLVs follow + */ + tlvlist = aim_readtlvchain(command->data+12, command->commandlen-12); - if ( (family == 0x0001) && - (subtype== 0x0003) ) - { - /* "server ready" -- can be ignored */ - userfunc = aim_callhandler(command->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY); - } - else if ( (family == 0x0007) && - (subtype== 0x0005) ) - { - /* "information change reply" */ - userfunc = aim_callhandler(command->conn, AIM_CB_FAM_ADM, AIM_CB_ADM_INFOCHANGE_REPLY); - } - else - { - /* anything else -- usually used for login; just parse as pure TLVs */ - - /* - * Free up the loginstruct first. - */ - sess->logininfo.screen_name[0] = '\0'; - if (sess->logininfo.BOSIP) - { - free(sess->logininfo.BOSIP); - sess->logininfo.BOSIP = NULL; - } - if (sess->logininfo.email) - { - free(sess->logininfo.email); - sess->logininfo.email = NULL; - } - sess->logininfo.regstatus = 0; - - /* all this block does is figure out if it's an - error or a success, nothing more */ - while (z < command->commandlen) - { - tlv = aim_grabtlvstr(&(command->data[z])); - switch(tlv->type) - { - case 0x0001: /* screen name */ - if (tlv->length >= MAXSNLEN) - { - /* SN too large... truncate */ - printf("faim: login: screen name from OSCAR too long! (%d)\n", tlv->length); - strncpy(sess->logininfo.screen_name, tlv->value, MAXSNLEN); - } - else - strncpy(sess->logininfo.screen_name, tlv->value, tlv->length); - z += 2 + 2 + tlv->length; - free(tlv); - tlv = NULL; - break; - case 0x0004: /* error URL */ - errorurl = tlv->value; - z += 2 + 2 + tlv->length; - free(tlv); - tlv = NULL; - break; - case 0x0005: /* BOS IP */ - sess->logininfo.BOSIP = tlv->value; - z += 2 + 2 + tlv->length; - free(tlv); - tlv = NULL; - break; - case 0x0006: /* auth cookie */ - memcpy(sess->logininfo.cookie, tlv->value, AIM_COOKIELEN); - z += 2 + 2 + tlv->length; - free(tlv); - tlv=NULL; - break; - case 0x0011: /* email addy */ - sess->logininfo.email = tlv->value; - z += 2 + 2 + tlv->length; - free(tlv); - tlv = NULL; - break; - case 0x0013: /* registration status */ - sess->logininfo.regstatus = *(tlv->value); - z += 2 + 2 + tlv->length; - aim_freetlv(&tlv); - break; - case 0x0008: /* error code */ - errorcode = *(tlv->value); - z += 2 + 2 + tlv->length; - aim_freetlv(&tlv); - iserror = 1; - break; - default: - z += 2 + 2 + tlv->length; - aim_freetlv(&tlv); - /* dunno */ - } - } + msg = aim_gettlv_str(tlvlist, 0x000b, 1); + + userfunc = aim_callhandler(command->conn, 0x0001, 0x0013); + if (userfunc) + ret = userfunc(sess, command, id, msg); - if (iserror && - errorurl) - { - userfunc = aim_callhandler(command->conn, AIM_CB_FAM_GEN, AIM_CB_GEN_ERROR); - if (userfunc) - return userfunc(sess, command, errorurl, errorcode); - return 0; - } - else if (sess->logininfo.screen_name[0] && - sess->logininfo.cookie[0] && sess->logininfo.BOSIP) - { - userfunc = aim_callhandler(command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_AUTHSUCCESS); - if (userfunc) - return userfunc(sess, command); - return 0; - } - else - userfunc = aim_callhandler(command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_AUTHOTHER); - } + aim_freetlvchain(&tlvlist); - if (userfunc) - return userfunc(sess, command); - printf("handler not available!\n"); - return 0; + return ret; + } -/* - * TODO: check for and cure any memory leaks here. - */ int aim_handleredirect_middle(struct aim_session_t *sess, struct command_rx_struct *command, ...) { - struct aim_tlv_t *tlv = NULL; - u_int z = 10; + struct aim_tlv_t *tmptlv = NULL; int serviceid = 0x00; - char *cookie = NULL; + char cookie[AIM_COOKIELEN]; char *ip = NULL; rxcallback_t userfunc = NULL; + struct aim_tlvlist_t *tlvlist; + int ret = 1; + + tlvlist = aim_readtlvchain(command->data+10, command->commandlen-10); + + tmptlv = aim_gettlv(tlvlist, 0x000d, 1); + serviceid = aimutil_get16(tmptlv->value); + + ip = aim_gettlv_str(tlvlist, 0x0005, 1); + + tmptlv = aim_gettlv(tlvlist, 0x0006, 1); + memcpy(cookie, tmptlv->value, AIM_COOKIELEN); - while (z < command->commandlen) - { - tlv = aim_grabtlvstr(&(command->data[z])); - switch(tlv->type) - { - case 0x000d: /* service id */ - aim_freetlv(&tlv); - /* regrab as an int */ - tlv = aim_grabtlv(&(command->data[z])); - serviceid = aimutil_get16(tlv->value); - z += 2 + 2 + tlv->length; - aim_freetlv(&tlv); - break; - case 0x0005: /* service server IP */ - ip = tlv->value; - z += 2 + 2 + tlv->length; - free(tlv); - tlv = NULL; - break; - case 0x0006: /* auth cookie */ - cookie = tlv->value; - z += 2 + 2 + tlv->length; - free(tlv); - tlv = NULL; - break; - default: - /* dunno */ - z += 2 + 2 + tlv->length; - aim_freetlv(&tlv); - } - } userfunc = aim_callhandler(command->conn, 0x0001, 0x0005); if (userfunc) - return userfunc(sess, command, serviceid, ip, cookie); - return 0; + ret = userfunc(sess, command, serviceid, ip, cookie); + + aim_freetlvchain(&tlvlist); + + return ret; } int aim_parse_unknown(struct aim_session_t *sess, diff --git a/aim_tlv.c b/aim_tlv.c index 53dc55d..94acf03 100644 --- a/aim_tlv.c +++ b/aim_tlv.c @@ -188,3 +188,26 @@ int aim_puttlv_16(u_char *buf, u_short t, u_short v) curbyte += aimutil_put16(buf+curbyte, (u_short)(v&0xffff)); return curbyte; } + +int aim_puttlv_32(u_char *buf, u_short t, u_long v) +{ + int curbyte=0; + curbyte += aimutil_put16(buf+curbyte, (u_short)(t&0xffff)); + curbyte += aimutil_put16(buf+curbyte, (u_short)0x0004); + curbyte += aimutil_put32(buf+curbyte, (u_long)(v&0xffffffff)); + return curbyte; +} + +int aim_puttlv_str(u_char *buf, u_short t, u_short l, u_char *v) +{ + int curbyte; + if (!v || !buf) + return 0; + + curbyte = 0; + curbyte += aimutil_put16(buf+curbyte, (u_short)(t&0xffff)); + curbyte += aimutil_put16(buf+curbyte, (u_short)(l&0xffff)); + memcpy(buf+curbyte, v, l); + curbyte += l; + return curbyte; +} diff --git a/faim/aim.h b/faim/aim.h index 9c790d5..38450f3 100644 --- a/faim/aim.h +++ b/faim/aim.h @@ -62,6 +62,8 @@ struct aim_login_struct { char cookie[AIM_COOKIELEN]; char *email; u_short regstatus; + char *errorurl; + u_short errorcode; }; /* @@ -225,6 +227,8 @@ int aim_puttlv (u_char *dest, struct aim_tlv_t *newtlv); struct aim_tlv_t *aim_createtlv(void); int aim_freetlv(struct aim_tlv_t **oldtlv); int aim_puttlv_16(u_char *, u_short, u_short); +int aim_puttlv_32(u_char *, u_short, u_long); +int aim_puttlv_str(u_char *buf, u_short t, u_short l, u_char *v); /* @@ -245,6 +249,8 @@ u_long aim_genericreq_l(struct aim_session_t *, struct aim_conn_t *conn, u_short u_long aim_genericreq_s(struct aim_session_t *, struct aim_conn_t *conn, u_short family, u_short subtype, u_short *); /* aim_login.c */ +int aim_sendconnack(struct aim_session_t *sess, struct aim_conn_t *conn); +int aim_request_login (struct aim_session_t *sess, struct aim_conn_t *conn, char *sn); int aim_send_login (struct aim_session_t *, struct aim_conn_t *, char *, char *, struct client_info_s *); int aim_encode_password(const char *, u_char *); @@ -335,6 +341,7 @@ int aim_handleredirect_middle(struct aim_session_t *, struct command_rx_struct * int aim_parse_unknown(struct aim_session_t *, struct command_rx_struct *, ...); int aim_parse_last_bad(struct aim_session_t *, struct command_rx_struct *, ...); int aim_parse_generalerrs(struct aim_session_t *, struct command_rx_struct *command, ...); +int aim_parsemotd_middle(struct aim_session_t *sess, struct command_rx_struct *command, ...); /* aim_im.c */ #define AIM_IMFLAGS_AWAY 0x01 /* mark as an autoreply */ diff --git a/faim/aim_cbtypes.h b/faim/aim_cbtypes.h index c900083..78b1ab5 100644 --- a/faim/aim_cbtypes.h +++ b/faim/aim_cbtypes.h @@ -23,6 +23,7 @@ #define AIM_CB_FAM_TRN 0x000c #define AIM_CB_FAM_CTN 0x000d /* ChatNav */ #define AIM_CB_FAM_CHT 0x000e /* Chat */ +#define AIM_CB_FAM_ATH 0x0017 #define AIM_CB_FAM_SPECIAL 0xffff /* Internal libfaim use */ /* @@ -160,6 +161,18 @@ #define AIM_CB_CHT_ERROR 0x0001 #define AIM_CB_CHT_DEFAULT 0xffff +/* + * SNAC Family: Authorizer + * + * Used only in protocol versions three and above. + * + */ +#define AIM_CB_ATH_ERROR 0x0001 +#define AIM_CB_ATH_LOGINREQEST 0x0002 +#define AIM_CB_ATH_LOGINRESPONSE 0x0003 +#define AIM_CB_ATH_AUTHREQ 0x0006 +#define AIM_CB_ATH_AUTHRESPONSE 0x0007 + /* * SNAC Family: Internal Messages * diff --git a/faim/faimconfig.h b/faim/faimconfig.h index 81ff626..395ed5a 100644 --- a/faim/faimconfig.h +++ b/faim/faimconfig.h @@ -22,9 +22,9 @@ /* * Maximum number of connections the library can simultaneously - * handle. Five is fairly arbitrary. Only one client that I - * know of uses more than one concurrently anyway (which means - * its only lightly tested too). + * handle per session structure. Five is fairly arbitrary. + * Only one client that I know of uses more than one concurrently + * anyway (which means its only lightly tested too). * * Default: 5 * @@ -49,11 +49,27 @@ * its a helluvalot of overhead for something that should * rarely happen. * - * Default: defined. + * Default: defined. This is now defined by default + * because it should be stable and its not too bad. + * And Josh wanted it. * */ #define USE_SNAC_FOR_IMS +/* + * As of AIM 3.5 or so, AOL as added a better way of + * logging in. Define this to use it instead of the + * old Version 1.0 way. + * + * The largest caveat here is that I have no idea + * how to encode passwords using the new 3.5 way. + * Until someone figures that out the... + * + * Default: Undefined. + * + */ +#undef SNACLOGIN + /* * Default Authorizer server name and TCP port for the OSCAR farm. * diff --git a/utils/faimtest/faimtest.c b/utils/faimtest/faimtest.c index f6d586f..00d6311 100644 --- a/utils/faimtest/faimtest.c +++ b/utils/faimtest/faimtest.c @@ -44,8 +44,8 @@ */ -#define FAIMTEST_SCREENNAME "ScreenName" -#define FAIMTEST_PASSWORD "PASS" +#define FAIMTEST_SCREENNAME "SCREENNAME" +#define FAIMTEST_PASSWORD "PASSWORD" #include @@ -53,7 +53,7 @@ int faimtest_parse_oncoming(struct aim_session_t *, struct command_rx_struct *, int faimtest_parse_offgoing(struct aim_session_t *, struct command_rx_struct *, ...); int faimtest_parse_login_phase3d_f(struct aim_session_t *, struct command_rx_struct *, ...); int faimtest_auth_error(struct aim_session_t *, struct command_rx_struct *, ...); -int faimtest_auth_success(struct aim_session_t *, struct command_rx_struct *, ...); +int faimtest_parse_authresp(struct aim_session_t *, struct command_rx_struct *, ...); int faimtest_parse_incoming_im(struct aim_session_t *, struct command_rx_struct *command, ...); int faimtest_parse_userinfo(struct aim_session_t *, struct command_rx_struct *command, ...); int faimtest_handleredirect(struct aim_session_t *, struct command_rx_struct *command, ...); @@ -61,14 +61,16 @@ int faimtest_authsvrready(struct aim_session_t *, struct command_rx_struct *comm int faimtest_pwdchngdone(struct aim_session_t *, struct command_rx_struct *command, ...); int faimtest_serverready(struct aim_session_t *, struct command_rx_struct *command, ...); int faimtest_parse_misses(struct aim_session_t *, struct command_rx_struct *command, ...); +int faimtest_parse_motd(struct aim_session_t *, struct command_rx_struct *command, ...); +int faimtest_parse_login(struct aim_session_t *, struct command_rx_struct *command, ...); int main(void) { struct aim_session_t aimsess; - struct client_info_s info = {"FAIMtest (Hi guys!)", 3, 90, 42, "us", "en"}; struct aim_conn_t *authconn = NULL; int stayconnected = 1; - + struct client_info_s info = {"FAIMtest (Hi guys!)", 3, 5, 1670, "us", "en"}; + aim_session_init(&aimsess); /* @@ -76,7 +78,7 @@ int main(void) * that reconnecting without restarting was actually possible...) */ enter: - authconn = aim_newconn(&aimsess, AIM_CONN_TYPE_AUTH, "127.0.0.1:5190"); + authconn = aim_newconn(&aimsess, AIM_CONN_TYPE_AUTH, FAIM_LOGIN_SERVER); if (authconn == NULL) { @@ -93,10 +95,19 @@ int main(void) } else { - aim_conn_addhandler(&aimsess, authconn, AIM_CB_FAM_GEN, AIM_CB_GEN_ERROR, faimtest_auth_error, 0); - aim_conn_addhandler(&aimsess, authconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_AUTHSUCCESS, faimtest_auth_success, 0); +#ifdef SNACLOGIN + /* new login code -- not default -- pending new password encryption algo */ + aim_conn_addhandler(&aimsess, authconn, 0x0017, 0x0007, faimtest_parse_login, 0); + aim_conn_addhandler(&aimsess, authconn, 0x0017, 0x0003, faimtest_parse_authresp, 0); + + aim_sendconnack(&aimsess, authconn); + aim_request_login(&aimsess, authconn, FAIMTEST_SCREENNAME); +#else + aim_conn_addhandler(&aimsess, authconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_AUTHSUCCESS, faimtest_parse_authresp, 0); aim_conn_addhandler(&aimsess, authconn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY, faimtest_authsvrready, 0); aim_send_login(&aimsess, authconn, FAIMTEST_SCREENNAME, FAIMTEST_PASSWORD, &info); + +#endif } while (aim_select(&aimsess, NULL) > (struct aim_conn_t *)0) @@ -144,6 +155,7 @@ int faimtest_serverready(struct aim_session_t *sess, struct command_rx_struct *c /* Request advertisement service -- see comment in handleredirect */ aim_bos_reqservice(sess, command->conn, AIM_CONN_TYPE_ADS); + aim_setversions(sess, command->conn); #if 0 aim_bos_reqrights(sess, command->conn); @@ -269,6 +281,7 @@ int faimtest_handleredirect(struct aim_session_t *sess, struct command_rx_struct return 1; } +#if 0 int faimtest_auth_error(struct aim_session_t *sess, struct command_rx_struct *command, ...) { va_list ap; @@ -288,15 +301,28 @@ int faimtest_auth_error(struct aim_session_t *sess, struct command_rx_struct *co return 0; } +#endif -int faimtest_auth_success(struct aim_session_t *sess, struct command_rx_struct *command, ...) +int faimtest_parse_authresp(struct aim_session_t *sess, struct command_rx_struct *command, ...) { struct aim_conn_t *bosconn = NULL; + printf("Screen name: %s\n", sess->logininfo.screen_name); + + /* + * Check for error. + */ + if (sess->logininfo.errorcode) + { + printf("Login Error Code 0x%04x\n", sess->logininfo.errorcode); + printf("Error URL: %s\n", sess->logininfo.errorurl); + aim_conn_close(command->conn); + exit(0); /* XXX: should return in order to let the above things get free()'d. */ + } + printf("Reg status: %2d\n", sess->logininfo.regstatus); printf("Email: %s\n", sess->logininfo.email); - printf("Cookie len: %d\n", sizeof(sess->logininfo.cookie)); printf("BOS IP: %s\n", sess->logininfo.BOSIP); printf("Closing auth connection...\n"); @@ -316,7 +342,6 @@ int faimtest_auth_success(struct aim_session_t *sess, struct command_rx_struct * aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY, faimtest_serverready, 0); aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_RATEINFO, NULL, 0); aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_REDIRECT, faimtest_handleredirect, 0); - aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_MOTD, NULL, 0); aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_STS, AIM_CB_STS_SETREPORTINTERVAL, NULL, 0); aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_ONCOMING, faimtest_parse_oncoming, 0); aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_OFFGOING, faimtest_parse_offgoing, 0); @@ -329,6 +354,7 @@ int faimtest_auth_success(struct aim_session_t *sess, struct command_rx_struct * aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_CTN, AIM_CB_CTN_DEFAULT, aim_parse_unknown, 0); aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_DEFAULT, aim_parse_unknown, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_MOTD, faimtest_parse_motd, 0); aim_auth_sendcookie(sess, bosconn, sess->logininfo.cookie); } return 1; @@ -539,6 +565,21 @@ int faimtest_parse_offgoing(struct aim_session_t *sess, struct command_rx_struct return 1; } +int faimtest_parse_motd(struct aim_session_t *sess, struct command_rx_struct *command, ...) +{ + char *msg; + u_short id; + va_list ap; + + va_start(ap, command); + id = va_arg(ap, u_short); + msg = va_arg(ap, char *); + va_end(ap); + + printf("faimtest: motd: %s\n", msg); + + return 1; +} /* * Handles callbacks for: AIM_CB_RATECHANGE, AIM_CB_USERERROR, @@ -579,7 +620,21 @@ int faimtest_parse_misses(struct aim_session_t *sess, struct command_rx_struct * return 0; } +#ifdef SNACLOGIN +int faimtest_parse_login(struct aim_session_t *sess, struct command_rx_struct *command, ...) +{ + struct client_info_s info = {"FAIMtest (Hi guys!)", 3, 5, 1670, "us", "en"}; + u_char authcookie[11]; + int i; + + for (i = 0; i < (int)command->data[11]; i++) + authcookie[i] = command->data[12+i]; + authcookie[i] = '\0'; - - - + printf("faimtest: logincookie: %s\n", authcookie); + + aim_send_login(sess, command->conn, FAIMTEST_SCREENNAME, FAIMTEST_PASSWORD, &info); + + return 1; +} +#endif -- 2.45.2