*/
#include "faimtest.h"
+#include <sys/stat.h>
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, ...);
"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;
{
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);
int i;
int selstat = 0;
static int faimtest_mode = 0;
+ struct timeval tv;
+ time_t lastnop = 0;
screenname = getenv("SCREENNAME");
password = getenv("PASSWORD");
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;
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");
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);
}
}
}
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 */
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 || !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) {
+ if (!modname) {
+ dperror("memrequest: stat");
+ free(filename);
+ return -1;
+ }
+ invalid = 1;
+ }
+
+ if (!invalid) {
+ if ((offset > st.st_size) || (len > 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) {
+ int i;
+
+ free(filename); /* not needed */
+
+ dvprintf("memrequest: recieved invalid request for 0x%08lx bytes at 0x%08lx (file %s)\n", len, offset, modname);
+
+ i = 8;
+ if (modname)
+ i += strlen(modname);
+
+ if (!(buf = malloc(i)))
+ return -1;
+
+ i = 0;
+
+ if (modname) {
+ memcpy(buf, modname, strlen(modname));
+ i += strlen(modname);
+ }
+
+ /* Damn endianness. This must be little (LSB first) endian. */
+ buf[i++] = offset & 0xff;
+ buf[i++] = (offset >> 8) & 0xff;
+ buf[i++] = (offset >> 16) & 0xff;
+ buf[i++] = (offset >> 24) & 0xff;
+ buf[i++] = len & 0xff;
+ buf[i++] = (len >> 8) & 0xff;
+ buf[i++] = (len >> 16) & 0xff;
+ buf[i++] = (len >> 24) & 0xff;
+
+ *bufret = buf;
+ *buflenret = i;
+
+ } 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;
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);
} 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")) {
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;
} 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)) {
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);
}
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;
}
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;
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;
}