X-Git-Url: http://andersk.mit.edu/gitweb/libfaim.git/blobdiff_plain/e80a0fa9198d4acd23acebd7e1bd5f6113b469bb..83ae98f8f4a187c01e91c2533ba3e286c165d563:/utils/faimtest/faimtest.c diff --git a/utils/faimtest/faimtest.c b/utils/faimtest/faimtest.c index 2875afc..4c8db38 100644 --- a/utils/faimtest/faimtest.c +++ b/utils/faimtest/faimtest.c @@ -39,6 +39,7 @@ */ #include "faimtest.h" +#include static char *dprintf_ctime(void) { @@ -75,7 +76,7 @@ static char *dprintf_ctime(void) 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_parse_authresp(struct aim_session_t *, struct command_rx_struct *, ...); +static 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, ...); @@ -148,6 +149,7 @@ static char *msgerrreasons[] = { "Not while on AOL"}; static int msgerrreasonslen = 25; +static char *aimbinarypath = NULL; static char *screenname,*password,*server=NULL; static char *proxy = NULL, *proxyusername = NULL, *proxypass = NULL; static char *ohcaptainmycaptain = NULL; @@ -259,7 +261,7 @@ int logout(void) { if (ohcaptainmycaptain) - aim_send_im(&aimsess, aim_getconn_type(&aimsess, AIM_CONN_TYPE_BOS), ohcaptainmycaptain, 0, "ta ta..."); + aim_send_im(&aimsess, aim_getconn_type(&aimsess, AIM_CONN_TYPE_BOS), ohcaptainmycaptain, 0, "ta ta...", strlen("ta ta...")); aim_session_kill(&aimsess); @@ -319,6 +321,8 @@ int main(int argc, char **argv) int i; int selstat = 0; static int faimtest_mode = 0; + struct timeval tv; + time_t lastnop = 0; screenname = getenv("SCREENNAME"); password = getenv("PASSWORD"); @@ -329,7 +333,7 @@ int main(int argc, char **argv) listingpath = getenv("LISTINGPATH"); - while ((i = getopt(argc, argv, "u:p:a:U:P:A:l:c:hoO")) != EOF) { + while ((i = getopt(argc, argv, "u:p:a:U:P:A:l:c:hoOb:")) != EOF) { switch (i) { case 'u': screenname = optarg; break; case 'p': password = optarg; break; @@ -341,6 +345,7 @@ int main(int argc, char **argv) case 'c': ohcaptainmycaptain = optarg; break; case 'o': faimtest_mode = 1; break; /* half old interface */ case 'O': faimtest_mode = 2; break; /* full old interface */ + case 'b': aimbinarypath = optarg; break; case 'h': default: printf("faimtest\n"); @@ -355,6 +360,7 @@ int main(int argc, char **argv) printf(" -c name Screen name of owner\n"); printf(" -o Login at startup, then prompt\n"); printf(" -O Login, never give prompt\n"); + printf(" -b path Path to AIM 3.5.1670 binaries\n"); exit(0); } } @@ -398,12 +404,21 @@ int main(int argc, char **argv) } while (keepgoing) { - waitingconn = aim_select(&aimsess, NULL, &selstat); + + tv.tv_sec = 5; + tv.tv_usec = 0; + + waitingconn = aim_select(&aimsess, &tv, &selstat); + + if (connected && ((time(NULL) - lastnop) > 30)) { + lastnop = time(NULL); + aim_flap_nop(&aimsess, aim_getconn_type(&aimsess, AIM_CONN_TYPE_BOS)); + } if (selstat == -1) { /* error */ keepgoing = 0; /* fall through */ } else if (selstat == 0) { /* no events pending */ - keepgoing = 0; + ; } else if (selstat == 1) { /* outgoing data pending */ aim_tx_flushqueue(&aimsess); } else if (selstat == 2) { /* incoming data pending */ @@ -784,7 +799,177 @@ int faimtest_handleredirect(struct aim_session_t *sess, struct command_rx_struct return 1; } -int faimtest_parse_authresp(struct aim_session_t *sess, struct command_rx_struct *command, ...) +/* + * This is a little more complicated than it looks. The module + * name (proto, boscore, etc) may or may not be given. If it is + * not given, then use aim.exe. If it is given, put ".ocm" on the + * end of it. + * + * Now, if the offset or length requested would cause a read past + * the end of the file, then the request is considered invalid. Invalid + * requests are processed specially. The value hashed is the + * the request, put into little-endian (eight bytes: offset followed + * by length). + * + * Additionally, if the request is valid, the length is mod 4096. It is + * important that the length is checked for validity first before doing + * the mod. + * + * Note to Bosco's Brigade: if you'd like to break this, put the + * module name on an invalid request. + * + */ +static int getaimdata(unsigned char **bufret, int *buflenret, unsigned long offset, unsigned long len, const char *modname) +{ + FILE *f; + static const char defaultmod[] = "aim.exe"; + char *filename = NULL; + struct stat st; + unsigned char *buf; + int invalid = 0; + + if (!bufret || !*bufret || !buflenret) + return -1; + + if (modname) { + + if (!(filename = malloc(strlen(aimbinarypath)+1+strlen(modname)+4+1))) { + dperror("memrequest: malloc"); + return -1; + } + + sprintf(filename, "%s/%s.ocm", aimbinarypath, modname); + + } else { + + if (!(filename = malloc(strlen(aimbinarypath)+1+strlen(defaultmod)+1))) { + dperror("memrequest: malloc"); + return -1; + } + + sprintf(filename, "%s/%s", aimbinarypath, defaultmod); + + } + + if (stat(filename, &st) == -1) { + dperror("memrequest: stat"); + free(filename); + return -1; + } + + if ((offset > st.st_size) || (offset > st.st_size)) + invalid = 1; + else if ((st.st_size - offset) < len) + len = st.st_size - offset; + else if ((st.st_size - len) < len) + len = st.st_size - len; + + if (!invalid && len) + len %= 4096; + + if (invalid) { + + free(filename); /* not needed */ + + if (!(buf = malloc(8))) + return -1; + + dvprintf("memrequest: recieved invalid request for 0x%08lx bytes at 0x%08lx\n", len, offset); + + /* Damn endianness. This must be little (LSB first) endian. */ + buf[0] = offset & 0xff; + buf[1] = (offset >> 8) & 0xff; + buf[2] = (offset >> 16) & 0xff; + buf[3] = (offset >> 24) & 0xff; + buf[4] = len & 0xff; + buf[5] = (len >> 8) & 0xff; + buf[6] = (len >> 16) & 0xff; + buf[7] = (len >> 24) & 0xff; + + *bufret = buf; + *buflenret = 8; + + } else { + + if (!(buf = malloc(len))) { + free(filename); + return -1; + } + + dvprintf("memrequest: loading %ld bytes from 0x%08lx in \"%s\"...\n", len, offset, filename); + + if (!(f = fopen(filename, "r"))) { + dperror("memrequest: fopen"); + free(filename); + free(buf); + return -1; + } + + free(filename); + + if (fseek(f, offset, SEEK_SET) == -1) { + dperror("memrequest: fseek"); + fclose(f); + free(buf); + return -1; + } + + if (fread(buf, len, 1, f) != 1) { + dperror("memrequest: fread"); + fclose(f); + free(buf); + return -1; + } + + fclose(f); + + *bufret = buf; + *buflenret = len; + + } + + return 0; /* success! */ +} + +/* + * This will get an offset and a length. The client should read this + * data out of whatever AIM.EXE binary the user has provided (hopefully + * it matches the client information thats sent at login) and pass a + * buffer back to libfaim so it can hash the data and send it to AOL for + * inspection by the client police. + */ +static int faimtest_memrequest(struct aim_session_t *sess, struct command_rx_struct *command, ...) +{ + va_list ap; + unsigned long offset, len; + char *modname; + unsigned char *buf; + int buflen; + + va_start(ap, command); + offset = va_arg(ap, unsigned long); + len = va_arg(ap, unsigned long); + modname = va_arg(ap, char *); + va_end(ap); + + if (aimbinarypath && (getaimdata(&buf, &buflen, offset, len, modname) == 0)) { + + aim_sendmemblock(sess, command->conn, offset, buflen, buf, AIM_SENDMEMBLOCK_FLAG_ISREQUEST); + + free(buf); + + } else { + + dvprintf("memrequest: unable to use AIM binary (\"%s/%s\"), sending defaults...\n", aimbinarypath, modname); + + aim_sendmemblock(sess, command->conn, offset, len, NULL, AIM_SENDMEMBLOCK_FLAG_ISREQUEST); + + } + + return 1; +} + +static int faimtest_parse_authresp(struct aim_session_t *sess, struct command_rx_struct *command, ...) { va_list ap; struct aim_conn_t *bosconn = NULL; @@ -881,7 +1066,8 @@ int faimtest_parse_authresp(struct aim_session_t *sess, struct command_rx_struct aim_conn_addhandler(sess, bosconn, 0x0009, 0x0001, faimtest_parse_genericerr, 0); aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR, faimtest_parse_connerr, 0); - + aim_conn_addhandler(sess, bosconn, 0x0001, 0x001f, faimtest_memrequest, 0); + aim_conn_addhandler(sess, bosconn, 0xffff, 0xffff, faimtest_parse_unknown, 0); aim_auth_sendcookie(sess, bosconn, cookie); @@ -955,7 +1141,7 @@ static int faimtest_handlecmd(struct aim_session_t *sess, struct command_rx_stru } else if (strstr(tmpstr, "goodday")) { - aim_send_im(sess, command->conn, userinfo->sn, AIM_IMFLAGS_ACK, "Good day to you too."); + aim_send_im(sess, command->conn, userinfo->sn, AIM_IMFLAGS_ACK, "Good day to you too.", strlen("Good day to you too.")); } else if (strstr(tmpstr, "warnme")) { @@ -981,7 +1167,7 @@ static int faimtest_handlecmd(struct aim_session_t *sess, struct command_rx_stru if (!ohcaptainmycaptain) { - aim_send_im(sess, command->conn, userinfo->sn, AIM_IMFLAGS_ACK, "I have no owner!"); + aim_send_im(sess, command->conn, userinfo->sn, AIM_IMFLAGS_ACK, "I have no owner!", strlen("I have no owner!")); } else { struct aim_conn_t *newconn; @@ -1035,7 +1221,7 @@ static int faimtest_handlecmd(struct aim_session_t *sess, struct command_rx_stru } else if (!strncmp(tmpstr, "reqsendmsg", 10)) { - aim_send_im(sess, command->conn, ohcaptainmycaptain, 0, "sendmsg 7900"); + aim_send_im(sess, command->conn, ohcaptainmycaptain, 0, "sendmsg 7900", strlen("sendmsg 7900")); } else if (!strncmp(tmpstr, "reqauth", 7)) { @@ -1069,7 +1255,7 @@ static int faimtest_handlecmd(struct aim_session_t *sess, struct command_rx_stru newbuf[z] = (z % 10)+0x30; } newbuf[i] = '\0'; - aim_send_im(sess, command->conn, userinfo->sn, 0, newbuf); + aim_send_im(sess, command->conn, userinfo->sn, 0, newbuf, strlen(newbuf)); free(newbuf); } @@ -1472,15 +1658,25 @@ int faimtest_parse_oncoming(struct aim_session_t *sess, struct command_rx_struct int faimtest_parse_offgoing(struct aim_session_t *sess, struct command_rx_struct *command, ...) { - char *sn; + struct aim_userinfo_s *userinfo; + va_list ap; - va_start(ap, command); - sn = va_arg(ap, char *); + userinfo = va_arg(ap, struct aim_userinfo_s *); va_end(ap); - dvprintf("\n%s has left\n", sn); - + dvprintf("%ld %s is now offline (flags: %04x = %s%s%s%s%s%s%s%s) (caps = 0x%04x)\n", + time(NULL), + userinfo->sn, userinfo->flags, + (userinfo->flags&AIM_FLAG_UNCONFIRMED)?" UNCONFIRMED":"", + (userinfo->flags&AIM_FLAG_ADMINISTRATOR)?" ADMINISTRATOR":"", + (userinfo->flags&AIM_FLAG_AOL)?" AOL":"", + (userinfo->flags&AIM_FLAG_OSCAR_PAY)?" OSCAR_PAY":"", + (userinfo->flags&AIM_FLAG_FREE)?" FREE":"", + (userinfo->flags&AIM_FLAG_AWAY)?" AWAY":"", + (userinfo->flags&AIM_FLAG_UNKNOWN40)?" UNKNOWN40":"", + (userinfo->flags&AIM_FLAG_UNKNOWN80)?" UNKNOWN80":"", + userinfo->capabilities); return 1; } @@ -1518,10 +1714,6 @@ int faimtest_parse_motd(struct aim_session_t *sess, struct command_rx_struct *co aim_0002_000b(sess, command->conn, sess->sn); #endif - /* As of 26 Mar 2001 you need to send this to keep from getting kicked off */ - aim_0001_0020(sess, command->conn); - - return 1; } @@ -1715,7 +1907,7 @@ int faimtest_chat_incomingmsg(struct aim_session_t *sess, struct command_rx_stru if (strcmp(userinfo->sn, sess->sn) != 0) { sprintf(tmpbuf, "(%s said \"%s\")", userinfo->sn, msg); - aim_chat_send_im(sess, command->conn, tmpbuf); + aim_chat_send_im(sess, command->conn, 0, tmpbuf, strlen(tmpbuf)); } return 1; @@ -1797,6 +1989,8 @@ int faimtest_parse_connerr(struct aim_session_t *sess, struct command_rx_struct dvprintf("faimtest: connerr: Code 0x%04x: %s\n", code, msg); aim_conn_kill(sess, &command->conn); /* this will break the main loop */ + connected = 0; + return 1; }