From e50124508689661c935f5d29e27bef3178e9326c Mon Sep 17 00:00:00 2001 From: mid Date: Mon, 26 Jun 2000 08:09:09 +0000 Subject: [PATCH] - Mon Jun 26 07:53:02 UTC 2000 - Added utils/aimdebugd for playing with things -- see the README - Added aim_im.c::aim_parse_outgoing_im(). Probably not useful unless you're writing a server or something (or hacking aimdebugd). - aim_send_im() now sends the same data as AIM4 does (three more bytes) - Added aim_debugconn_sendconnect() for aimdebugd-enablement. --- CHANGES | 7 ++ aim_im.c | 85 ++++++++++++- aim_misc.c | 11 ++ aim_rxhandlers.c | 11 ++ faim/aim.h | 4 +- faim/aim_cbtypes.h | 1 + tcpdumps/newim.txt | 28 ++++- utils/Makefile | 10 +- utils/aimdebugd/Makefile | 15 +++ utils/aimdebugd/README | 70 +++++++++++ utils/aimdebugd/aimdebugd.c | 229 +++++++++++++++++++++++++++++++++++ utils/aimdebugd/file.c | 101 +++++++++++++++ utils/aimdebugd/icbm.c | 106 ++++++++++++++++ utils/aimdebugd/network.c | 126 +++++++++++++++++++ utils/aimdebugd/network.h | 8 ++ utils/aimdebugd/samplescript | 5 + utils/faimtest/faimtest.c | 18 +++ 17 files changed, 821 insertions(+), 14 deletions(-) create mode 100644 utils/aimdebugd/Makefile create mode 100644 utils/aimdebugd/README create mode 100644 utils/aimdebugd/aimdebugd.c create mode 100644 utils/aimdebugd/file.c create mode 100644 utils/aimdebugd/icbm.c create mode 100644 utils/aimdebugd/network.c create mode 100644 utils/aimdebugd/network.h create mode 100644 utils/aimdebugd/samplescript diff --git a/CHANGES b/CHANGES index 3dabe0a..dd976bc 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,13 @@ No release numbers ------------------ + - Mon Jun 26 07:53:02 UTC 2000 + - Added utils/aimdebugd for playing with things -- see the README + - Added aim_im.c::aim_parse_outgoing_im(). Probably not useful + unless you're writing a server or something (or hacking aimdebugd). + - aim_send_im() now sends the same data as AIM4 does (three more bytes) + - Added aim_debugconn_sendconnect() for aimdebugd-enablement. + - Sat Jun 24 02:14:07 UTC 2000 - Added fakelocks for platforms without pthreads or that have no use for them. diff --git a/aim_im.c b/aim_im.c index f82ecfa..8c61908 100644 --- a/aim_im.c +++ b/aim_im.c @@ -64,15 +64,22 @@ u_long aim_send_im(struct aim_session_t *sess, * metaTLV start. */ curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002); - curbyte += aimutil_put16(newpacket->data+curbyte, strlen(msg) + 0x0d); + curbyte += aimutil_put16(newpacket->data+curbyte, strlen(msg) + 0x10); /* - * Flag data? + * Flag data / ICBM Parameters? */ - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0501); - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001); + curbyte += aimutil_put8(newpacket->data+curbyte, 0x05); + curbyte += aimutil_put8(newpacket->data+curbyte, 0x01); + + /* number of bytes to follow */ + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0004); + curbyte += aimutil_put8(newpacket->data+curbyte, 0x01); + curbyte += aimutil_put8(newpacket->data+curbyte, 0x01); + curbyte += aimutil_put8(newpacket->data+curbyte, 0x01); + curbyte += aimutil_put8(newpacket->data+curbyte, 0x02); + curbyte += aimutil_put16(newpacket->data+curbyte, 0x0101); - curbyte += aimutil_put8 (newpacket->data+curbyte, 0x01); /* * Message block length. @@ -214,6 +221,74 @@ int aim_send_im_direct(struct aim_session_t *sess, return 0; } +int aim_parse_outgoing_im_middle(struct aim_session_t *sess, + struct command_rx_struct *command) +{ + unsigned int i = 0, z; + rxcallback_t userfunc = NULL; + unsigned char cookie[8]; + int channel; + struct aim_tlvlist_t *tlvlist; + char sn[MAXSNLEN]; + unsigned short icbmflags = 0; + unsigned char flag1 = 0, flag2 = 0; + unsigned char *msgblock = NULL, *msg = NULL; + + i = 10; + + /* ICBM Cookie. */ + for (z=0; z<8; z++,i++) + cookie[z] = command->data[i]; + + /* Channel ID */ + channel = aimutil_get16(command->data+i); + i += 2; + + if (channel != 0x01) { + printf("faim: icbm: ICBM recieved on unsupported channel. Ignoring. (chan = %04x)\n", channel); + return 1; + } + + strncpy(sn, command->data+i+1, (int) *(command->data+i)); + i += 1 + (int) *(command->data+i); + + tlvlist = aim_readtlvchain(command->data+i, command->commandlen-i); + + if (aim_gettlv(tlvlist, 0x0003, 1)) + icbmflags |= AIM_IMFLAGS_ACK; + if (aim_gettlv(tlvlist, 0x0004, 1)) + icbmflags |= AIM_IMFLAGS_AWAY; + + if (aim_gettlv(tlvlist, 0x0002, 1)) { + int j = 0; + + msgblock = aim_gettlv_str(tlvlist, 0x0002, 1); + + /* no, this really is correct. I'm not high or anything either. */ + j += 2; + j += 2 + aimutil_get16(msgblock+j); + j += 2; + + j += 2; /* final block length */ + + flag1 = aimutil_get16(msgblock); + j += 2; + flag2 = aimutil_get16(msgblock); + j += 2; + + msg = msgblock+j; + } + + if ((userfunc = aim_callhandler(command->conn, 0x0004, 0x0006)) || (i = 0)) + i = userfunc(sess, command, channel, sn, msg, icbmflags, flag1, flag2); + + if (msgblock) + free(msgblock); + aim_freetlvchain(&tlvlist); + + return 0; +} + /* * It can easily be said that parsing ICBMs is THE single * most difficult thing to do in the in AIM protocol. In diff --git a/aim_misc.c b/aim_misc.c index a909eb3..420165f 100644 --- a/aim_misc.c +++ b/aim_misc.c @@ -539,6 +539,17 @@ u_long aim_bos_reqbuddyrights(struct aim_session_t *sess, return aim_genericreq_n(sess, conn, 0x0003, 0x0002); } +/* + * aim_debugconn_sendconnect() + * + * For aimdebugd. If you don't know what it is, you don't want to. + */ +u_long aim_debugconn_sendconnect(struct aim_session_t *sess, + struct aim_conn_t *conn) +{ + return aim_genericreq_n(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_DEBUGCONN_CONNECT); +} + /* * Generic routine for sending commands. * diff --git a/aim_rxhandlers.c b/aim_rxhandlers.c index 7c0b00c..736fd83 100644 --- a/aim_rxhandlers.c +++ b/aim_rxhandlers.c @@ -372,6 +372,11 @@ int aim_rxdispatch(struct aim_session_t *sess) if (subtype == 0x0005) workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_ADM, AIM_CB_ADM_INFOCHANGE_REPLY, workingPtr); break; + case AIM_CB_FAM_SPECIAL: + if (subtype == AIM_CB_SPECIAL_DEBUGCONN_CONNECT) { + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr); + break; + } /* others fall through */ default: /* Old login protocol */ /* any user callbacks will be called from here */ @@ -468,6 +473,9 @@ int aim_rxdispatch(struct aim_session_t *sess) case 0x0005: workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, 0x0004, 0x0005, workingPtr); break; + case 0x0006: + workingPtr->handled = aim_parse_outgoing_im_middle(sess, workingPtr); + break; case 0x0007: workingPtr->handled = aim_parse_incoming_im_middle(sess, workingPtr); break; @@ -506,6 +514,9 @@ int aim_rxdispatch(struct aim_session_t *sess) else workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_STS, AIM_CB_STS_DEFAULT, workingPtr); break; + case AIM_CB_FAM_SPECIAL: + workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, family, subtype, workingPtr); + break; default: workingPtr->handled = aim_callhandler_noparam(sess, workingPtr->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_UNKNOWN, workingPtr); break; diff --git a/faim/aim.h b/faim/aim.h index 6d6ec25..dce12e4 100644 --- a/faim/aim.h +++ b/faim/aim.h @@ -359,7 +359,8 @@ int aim_counttlvchain(struct aim_tlvlist_t **list); */ int aim_get_command(struct aim_session_t *, struct aim_conn_t *); int aim_rxdispatch(struct aim_session_t *); - +u_long aim_debugconn_sendconnect(struct aim_session_t *sess, + struct aim_conn_t *conn); int aim_logoff(struct aim_session_t *); void aim_conn_kill(struct aim_session_t *sess, struct aim_conn_t **deadconn); @@ -490,6 +491,7 @@ int aim_parsemotd_middle(struct aim_session_t *sess, struct command_rx_struct *c u_long aim_send_im(struct aim_session_t *, struct aim_conn_t *, char *, u_int, char *); int aim_parse_incoming_im_middle(struct aim_session_t *, struct command_rx_struct *); +int aim_parse_outgoing_im_middle(struct aim_session_t *, struct command_rx_struct *); u_long aim_seticbmparam(struct aim_session_t *, struct aim_conn_t *conn); int aim_parse_msgerror_middle(struct aim_session_t *, struct command_rx_struct *); int aim_negchan_middle(struct aim_session_t *sess, struct command_rx_struct *command); diff --git a/faim/aim_cbtypes.h b/faim/aim_cbtypes.h index 9c0e773..3943e10 100644 --- a/faim/aim_cbtypes.h +++ b/faim/aim_cbtypes.h @@ -191,6 +191,7 @@ #define AIM_CB_SPECIAL_AUTHSUCCESS 0x0001 #define AIM_CB_SPECIAL_AUTHOTHER 0x0002 #define AIM_CB_SPECIAL_CONNERR 0x0003 +#define AIM_CB_SPECIAL_DEBUGCONN_CONNECT 0xe001 #define AIM_CB_SPECIAL_UNKNOWN 0xffff #define AIM_CB_SPECIAL_DEFAULT AIM_CB_SPECIAL_UNKNOWN diff --git a/tcpdumps/newim.txt b/tcpdumps/newim.txt index a02544d..8e559f9 100644 --- a/tcpdumps/newim.txt +++ b/tcpdumps/newim.txt @@ -8,7 +8,12 @@ 096d 6964 656e 6469 616e 0003 0000 -0002 003a 0501 0003 01 01 01 01 01 +0002 003a + 05 + 01 + 0003 + 0101 01 + 0101 002f 00 0000 00 @@ -32,3 +37,24 @@ G=47 o=6f o=6f d=64 =20 d=64 a=61 y=79 =20 t=74 o=6f =20 y=79 o=6f u=75 =20 t=74 o=6f o=6f .=2e + +--------- + + 2a02 602f 006f + 0004 0006 0000 0000 8001 + 3135 3642 4538 3800 + 0001 + 06 xx xxxx xxxx xx + 0002 0050 + 0501 + 0004 + 0101 0102 + 0101 + 0044 + 0000 0000 + + 3c 4854 + 4d4c 3e3c 424f 4459 2042 4743 4f4c 4f52 + 3d22 2366 6666 6666 6622 3e3c 464f 4e54 + 3e6b 3b73 616a 6466 3c2f 464f 4e54 3e3c + 2f42 4f44 593e 3c2f 4854 4d4c 3e \ No newline at end of file diff --git a/utils/Makefile b/utils/Makefile index a0c92b8..9eac332 100644 --- a/utils/Makefile +++ b/utils/Makefile @@ -1,20 +1,16 @@ include Makefile.dynamicrules -UTIL_DIRS = faimtest #aimdump aimpasswd +UTIL_DIRS = faimtest aimdebugd #aimdump aimpasswd utils_all: @dirs='$(UTIL_DIRS)'; \ for i in $$dirs; do \ - cd $$i; \ - $(MAKE); \ - cd ..; \ + $(MAKE) -C $$i; \ done; clean: @dirs='$(UTIL_DIRS)'; \ for i in $$dirs; do \ - cd $$i; \ - $(MAKE) clean; \ - cd ..; \ + $(MAKE) -C $$i clean; \ done; @rm -f Makefile.dynamicrules diff --git a/utils/aimdebugd/Makefile b/utils/aimdebugd/Makefile new file mode 100644 index 0000000..3649a53 --- /dev/null +++ b/utils/aimdebugd/Makefile @@ -0,0 +1,15 @@ +include ../Makefile.dynamicrules +include $(LIBFAIM_LIB)/Makefile.rules + +EXEC_NAME = aimdebugd +EXEC_OBJECTS = \ + aimdebugd.o \ + network.o \ + file.o \ + icbm.o + +all: $(EXEC_OBJECTS) + $(CC) $(CFLAGS) -o $(EXEC_NAME) $(EXEC_OBJECTS) $(LDFLAGS) + +clean: + rm -f *~ $(EXEC_OBJECTS) $(EXEC_NAME) diff --git a/utils/aimdebugd/README b/utils/aimdebugd/README new file mode 100644 index 0000000..4977fec --- /dev/null +++ b/utils/aimdebugd/README @@ -0,0 +1,70 @@ + +aimdebugd. Slightly ambiguous name. Basically, its a +micro-aim-server thats meant to be hacked. Its completely useless the +way it is, but it does let you poke and prod at clients while they're +in their main loop. It won't help for debugging the login process, +but it will allow you to test various ICBM types, etc -- anything you +want to implement packet handlers and transmitters for. + +How to make your client work with aimdebugd +------------------------------------------- + 1. Create a handler for the debug connection SNAC like this: + +int debugconn_connect_handler(struct aim_session_t *sess, struct command_rx_struct *command, ...) { + + printf("connecting to an aimdebugd!\n"); + + /* convert the authorizer connection to a BOS connection */ + command->conn->type = AIM_CONN_TYPE_BOS; + + /* You may want to add some of your BOS callbacks here */ + + /* tell the aimdebugd we're ready */ + aim_debugconn_sendconnect(sess, command->conn); + + /* go right into main loop (don't open a BOS connection, etc) */ + return 1; +} + + 2. Connect the handler to your authorizer connection before + calling aim_send_login() or aim_select(): + + ... + aim_conn_addhandler(sess, authconn, AIM_CB_FAM_SPECIAL, + AIM_CB_SPECIAL_DEBUGCONN_CONNECT, + debugconn_connect_handler, 0); + ... + + 3. Start your client with the authorizer host set to the box + running the aimddebugd. + + +Writing Halfscripts +------------------- + +Some hacking of aimdebugd can be done without writing any C. But it +its write-only. + +Once aimdebugd gets the acknowledgment from the client, it can begin +to run through a file (passed through a command line) that contains a +listing of excruciatingly simple "commands" and react to it. The +commandset is very small, and, as mentioned above, is write-only -- +its not event driven. The list of commands is executed linearly and +does not stop until it hits the break command, hits the end of the +file, hits the disconnect command, or the connection to the client +dies. + +Commands: + # -- Comment + b -- Breaks execution, leaves connection open + d -- Disconnects from client (results in connection termination) + e -- Prints msg to stderr + m / -- Sends msg from srcsn to the client + s -- Sleeps for an arbitrary number of seconds + +Note that the client must have callbacks connected to the appropriate +handlers if it wants to react to any of the output from these commands +(except 'e', thats just there). + + + diff --git a/utils/aimdebugd/aimdebugd.c b/utils/aimdebugd/aimdebugd.c new file mode 100644 index 0000000..1779a4d --- /dev/null +++ b/utils/aimdebugd/aimdebugd.c @@ -0,0 +1,229 @@ + +#include +#include +#include +#include "network.h" + +#define RUNNAME "aimdebugd" +#define RUNPREFIX RUNNAME ": " + +typedef struct { + struct aim_session_t sess; +} client_t; + +int stayalive = 1; + +int clientready = 0; +int scriptfd = -1; + +void sigchld(int signum) +{ + pid_t pid; + int status; + + pid = wait(&status); + + return; +} + +int cb_login(struct aim_session_t *sess, struct command_rx_struct *command, ...) +{ + return 1; +} + +int incomingim(struct aim_session_t *sess, struct command_rx_struct *command, ...) +{ + int channel; + va_list ap; + + va_start(ap, command); + channel = va_arg(ap, int); + + if (channel == 1) { + char *sn = NULL; + char *msg = NULL; + u_int icbmflags = 0; + u_short flag1, flag2; + + sn = va_arg(ap, char *); + msg = va_arg(ap, char *); + icbmflags = va_arg(ap, u_int); + flag1 = va_arg(ap, u_short); + flag2 = va_arg(ap, u_short); + va_end(ap); + + printf("aimdebugd: client %d: %s/0x%04x/0x%02x/0x%02x/%s\n", + getpid(), + sn, + icbmflags, flag1, + flag2, msg); + + } else + printf("aimdebugd: client %d: unsupported ICBM channel %d\n", getpid(), channel); + + return 1; +} + +int debugconn_connect(struct aim_session_t *sess, struct command_rx_struct *command, ...) +{ + struct aim_conn_t *scriptconn; + + clientready = 1; + + if (!(scriptconn = aim_newconn(sess, 0, NULL))) { + printf(RUNPREFIX "unable to allocate script structures\n"); + aim_logoff(sess); + return 1; + } + scriptconn->fd = scriptfd; + + return 1; +} + +int parsescriptline(struct aim_session_t *sess, struct aim_conn_t **conn); /* file.c */ + +int handlechild(int fd, char *scriptname) +{ + int stayalive = 1, selstat; + client_t client; + struct aim_conn_t *inconn, *waitingconn; + + aim_session_init(&client.sess); + + if (!(inconn = aim_newconn(&client.sess, AIM_CONN_TYPE_BOS, NULL))) { + printf(RUNPREFIX "unable to allocate client structures\n"); + exit(-1); + } + inconn->fd = fd; + + if (scriptname) { + if (scriptname[0] == '-') + scriptfd = STDIN_FILENO; + else if ((scriptfd = open(scriptname, O_RDONLY)) < 0) { + perror(RUNPREFIX "open"); + return -1; + } + } + + aim_conn_addhandler(&client.sess, inconn, 0x0000, 0x0001, cb_login, 0); + aim_conn_addhandler(&client.sess, inconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_DEBUGCONN_CONNECT, debugconn_connect, 0); + aim_conn_addhandler(&client.sess, inconn, 0x0004, 0x0006, incomingim, 0); + + aim_debugconn_sendconnect(&client.sess, inconn); + + while (stayalive) { + waitingconn = aim_select(&client.sess, NULL, &selstat); + + switch(selstat) { + case -1: /* error */ + stayalive = 0; /* fall through and hit aim_logoff() */ + break; + case 0: /* nothing pending */ + break; + case 1: /* outgoing data pending */ + aim_tx_flushqueue(&client.sess); + break; + case 2: /* incoming data pending */ + if (waitingconn->fd == scriptfd) { + if (clientready) { + if (parsescriptline(&client.sess, &waitingconn) < 0) { + stayalive = 0; + } + } + } else { + if (aim_get_command(&client.sess, waitingconn) < 0) { + printf(RUNPREFIX "connection error\n"); + stayalive = 0; /* fall through to aim_logoff() */ + } else { + aim_rxdispatch(&client.sess); + } + } + break; + default: /* invalid */ + break; + } + } + + printf(RUNPREFIX "client disconnected\n"); + + aim_logoff(&client.sess); + + return fd; +} + +int main(int argc, char **argv) +{ + int listener = -1; + int client = -1; + int n; + char *scriptname = NULL; + int nofork = 0; + int runonce = 0, runsleft = 1; + + while ((n = getopt(argc, argv, "c:noh")) != EOF) { + switch(n) { + case 'c': + scriptname = optarg; + break; + case 'n': /* don't fork */ + nofork = 1; + break; + case 'o': /* run once only */ + runonce = 1; + break; + usage: + case 'h': + printf("aimdebugd v0.10 -- Adam Fritzler (mid@auk.cx)\n"); + printf("Usage:\n"); + printf("\taimdebugd [-c file] [-n] [-o]\n"); + printf("\t\t-c file\tScript file or - for stdin\n"); + printf("\t\t-n\tDo not fork for each client, process serially\n"); + printf("\t\t-o\tRun once and exit (required if script from stdin)\n"); + printf("\n"); + exit(2); + } + } + + if (scriptname && (scriptname[0] == '-') && (!nofork || !runonce)) { + printf(RUNPREFIX "stdin script is not valid without -n and -o\n"); + return -1; + } + + printf(RUNPREFIX "starting\n"); + + signal(SIGCHLD, sigchld); + + if ((listener = establish(5190)) < 0) { + perror(RUNPREFIX "establish"); + exit(-1); + } + + while (stayalive) { + if (runonce && !runsleft) + break; + if ((client = get_connection(listener)) < 0) { + perror(RUNPREFIX "get_connection"); + stayalive = 0; + } else { + runsleft--; + if (nofork) + handlechild(client, scriptname); + else { + switch(fork()) { + case -1: + perror(RUNPREFIX "fork"); + break; + case 0: + return handlechild(client, scriptname); + break; + default: + close(client); /* let the child have it */ + break; + } + } + } + } + + printf(RUNPREFIX "stopping\n"); + return 0; +} diff --git a/utils/aimdebugd/file.c b/utils/aimdebugd/file.c new file mode 100644 index 0000000..a8e9867 --- /dev/null +++ b/utils/aimdebugd/file.c @@ -0,0 +1,101 @@ + +#include + +static int readln(int fd, char *buf, int buflen) +{ + int i = 0; + int ret = 0; + + while ((i < buflen) && ((ret = read(fd, buf, 1)) > 0)) { + if (*buf == '\n') { + *buf = '\0'; + return i; + } + buf++; + i++; + } + + if (ret == 0) { + *buf = '\0'; + return i; + } + + if (ret == -1) + perror("read"); + + return -1; +} + +static inline char *killwhite(char *inbuf) +{ + char *buf; + buf = inbuf; + while(buf && ((*buf==' ') || (*buf=='\t'))) /* skip leading whitespace */ + buf++; + return buf; +} + +static inline char *nextwhite(char *inbuf) +{ + char *buf; + buf = inbuf; + while(buf) { + if ((*buf != ' ')) + buf++; + else + return buf; + } + return buf; +} + +int parsescriptline2(struct aim_session_t *sess, struct aim_conn_t **scriptconn, char *buf) +{ + if (!buf) + return 0; + + switch (buf[0]) { + case '#': /* comment */ + break; + case 'b': /* break */ + aim_conn_kill(sess, scriptconn); + break; + case 'd': /* disconnect */ + aim_conn_kill(sess, scriptconn); + aim_logoff(sess); + return -1; + break; + case 'e': /* print to stderr */ + buf = nextwhite(buf)+1; + fprintf(stderr, "%s\n", buf); + break; + case 'm': /* message */ + { + char *sn, *msg; + buf = nextwhite(buf)+1; + sn = strsep(&buf, "/"); + msg = strsep(&buf, "/"); + sendimtoclient(sess, aim_getconn_type(sess, AIM_CONN_TYPE_BOS), sn, 0, msg); + } + break; + case 's': /* sleep */ + buf = nextwhite(buf)+1; + printf("sleeping for %d seconds\n", atoi(buf)); + sleep(atoi(buf)); + break; + default: + printf("unknown script command %c\n", buf[0]); + break; + } + return 0; +} + +int parsescriptline(struct aim_session_t *sess, struct aim_conn_t **conn) +{ + char buf[256]; + if (readln((*conn)->fd, buf, 255) > 0) + return parsescriptline2(sess, conn, buf); + else { + aim_conn_kill(sess, conn); + } + return 0; +} diff --git a/utils/aimdebugd/icbm.c b/utils/aimdebugd/icbm.c new file mode 100644 index 0000000..db42969 --- /dev/null +++ b/utils/aimdebugd/icbm.c @@ -0,0 +1,106 @@ + +#include + +int sendimtoclient(struct aim_session_t *sess, struct aim_conn_t *conn, + char *srcsn, u_int flags, char *msg) +{ + struct command_tx_struct *tx; + struct aimd_clientinfo *client = NULL; + struct aim_tlvlist_t *tlvlist = NULL; + struct aim_tlvlist_t *tlvlist2 = NULL; + int i = 0, y, z; + char *msgblock; + + if (!(tx = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, strlen(msg)+256))) + return -1; + + tx->lock = 1; + + msgblock = malloc(strlen(msg)+128); /* ?? */ + memset(msgblock, 0, strlen(msg)+128); + + z = 0; + z += aimutil_put8(msgblock+z, 0x00); + z += aimutil_put8(msgblock+z, 0x00); + + z += aimutil_put16(msgblock+z, 0x02); + z += aimutil_put8(msgblock+z, 0x00); + z += aimutil_put8(msgblock+z, 0x00); + + z += aimutil_put8(msgblock+z, 0x00); + z += aimutil_put8(msgblock+z, 0x00); + + z += aimutil_put16(msgblock+z, strlen(msg)+4); + /* flag words */ + z += aimutil_put16(msgblock+z, 0x0000); + z += aimutil_put16(msgblock+z, 0x0000); + + /* msg */ + z += aimutil_putstr(msgblock+z, msg, strlen(msg)); + + /* + * SNAC header + */ + i = 0; + i += aimutil_put16(tx->data+i, 0x0004); + i += aimutil_put16(tx->data+i, 0x0007); + i += aimutil_put16(tx->data+i, 0x0000); + i += aimutil_put16(tx->data+i, 0x0000); + i += aimutil_put16(tx->data+i, 0x0000); + + /* + * Message cookie + */ + for (y=0;y<8;y++) + i += aimutil_put8(tx->data+i+y, (u_char) random()); + + /* + * Channel ID + */ + i += aimutil_put16(tx->data+i, 0x0001); + + /* + * Source SN + */ + i += aimutil_put8(tx->data+i, strlen(srcsn)); + i += aimutil_putstr(tx->data+i, srcsn, strlen(srcsn)); + + /* + * Warning level + */ + i += aimutil_put16(tx->data+i, 0x0000); + + /* class */ + aim_addtlvtochain16(&tlvlist, 0x0001, AIM_CLASS_FREE | AIM_CLASS_TRIAL); + + /* member-since date */ + aim_addtlvtochain32(&tlvlist, 0x0002, 0); + + /* on-since date */ + aim_addtlvtochain32(&tlvlist, 0x0003, 0); + + /* idle-time */ + aim_addtlvtochain16(&tlvlist, 0x0004, 0); + + /* session length (AIM) */ + aim_addtlvtochain16(&tlvlist, 0x000f, 0); + + /* add msgblock to chain */ + aim_addtlvtochain_str(&tlvlist2, 0x0002, msgblock, z); + + i += aimutil_put16(tx->data+i, aim_counttlvchain(&tlvlist)); + i += aim_writetlvchain(tx->data+i, tx->commandlen-i, &tlvlist); + tx->commandlen = aim_writetlvchain(tx->data+i, tx->commandlen-i, &tlvlist2)+i; + + + free(msgblock); + aim_freetlvchain(&tlvlist); + + tx->lock = 0; + + aim_tx_enqueue(sess, tx); + + sess->snac_nextid++; + + return 0; +} diff --git a/utils/aimdebugd/network.c b/utils/aimdebugd/network.c new file mode 100644 index 0000000..6c873b4 --- /dev/null +++ b/utils/aimdebugd/network.c @@ -0,0 +1,126 @@ +/* + * Misc network functions + * + */ + +#include + +int Read(int fd, unsigned char *buf, int len) +{ + int i = 0; + int j = 0; + int err_count=0; + + while ((i < len) && (!(i < 0))) + { + j = read(fd, &(buf[i]), len-i); + if ( (j < 0) && (errno != EAGAIN)) + return -errno; /* fail */ + else if (j==0) + { + err_count++; + if (err_count> 100) { + /* + * Reached maximum number of allowed read errors. + * + * Lets suppose the connection is lost and errno didn't + * know it. + * + */ + return (-1); + } + } + else + i += j; /* success, continue */ + } + return i; +} + +/* + * Create a listener socket. + * + * We go out of our way to make this interesting. (The Easy Way is not + * thread-safe.) + * + */ +int establish(u_short portnum) +{ + int listenfd; + const int on = 1; + struct addrinfo hints, *res, *ressave; + char serv[5]; + + sprintf(serv, "%d", portnum); + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + if (getaddrinfo(NULL/*any IP*/, serv, &hints, &res) != 0) { + perror("getaddrinfo"); + return -1; + } + + ressave = res; + do { + listenfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if (listenfd < 0) + continue; + setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + if (bind(listenfd, res->ai_addr, res->ai_addrlen) == 0) + break; /* sucess */ + close(listenfd); + } while ( (res = res->ai_next) ); + + if (!res) + return -1; + + if (listen(listenfd, 1024)!=0) { + perror("listen"); + return -1; + } + + freeaddrinfo(ressave); + + return listenfd; +} + +int get_connection(int s) +{ + struct sockaddr isa; + int addrlen = 0; + int t; /* socket of connection */ + + memset(&isa, 0, sizeof(struct sockaddr)); + if ((t = accept(s,&isa,&addrlen)) < 0) { + perror("accept"); + return -1; + } + + return t; +} + +int openconn(char *hostname, int port) +{ + struct sockaddr_in sa; + struct hostent *hp; + int ret; + + if (!(hp = gethostbyname(hostname))) { + perror("gethostbyname"); + return -1; + } + + memset(&sa.sin_zero, 0, 8); + sa.sin_port = htons(port); + memcpy(&sa.sin_addr, hp->h_addr, hp->h_length); + sa.sin_family = hp->h_addrtype; + + ret = socket(hp->h_addrtype, SOCK_STREAM, 0); + if (connect(ret, (struct sockaddr *)&sa, sizeof(struct sockaddr_in))<0) { + perror("connect"); + return -1; + } + + return ret; +} diff --git a/utils/aimdebugd/network.h b/utils/aimdebugd/network.h new file mode 100644 index 0000000..57cd97b --- /dev/null +++ b/utils/aimdebugd/network.h @@ -0,0 +1,8 @@ +/* + * Common functions used in all apps + */ + +int Read(int fd, unsigned char *buf, int len); +int establish(u_short portnum); +int get_connection(int s); +int openconn(char *hostname, int port); diff --git a/utils/aimdebugd/samplescript b/utils/aimdebugd/samplescript new file mode 100644 index 0000000..ab23ffa --- /dev/null +++ b/utils/aimdebugd/samplescript @@ -0,0 +1,5 @@ +# Simple test script +e Starting test script... +m bleu/goodday +e Breaking... +b diff --git a/utils/faimtest/faimtest.c b/utils/faimtest/faimtest.c index 4763eda..fc00748 100644 --- a/utils/faimtest/faimtest.c +++ b/utils/faimtest/faimtest.c @@ -65,6 +65,7 @@ int faimtest_chat_infoupdate(struct aim_session_t *sess, struct command_rx_struc int faimtest_chat_leave(struct aim_session_t *sess, struct command_rx_struct *command, ...); int faimtest_chat_join(struct aim_session_t *sess, struct command_rx_struct *command, ...); int faimtest_parse_connerr(struct aim_session_t *sess, struct command_rx_struct *command, ...); +int faimtest_debugconn_connect(struct aim_session_t *sess, struct command_rx_struct *command, ...); int faimtest_reportinterval(struct aim_session_t *sess, struct command_rx_struct *command, ...) { @@ -128,6 +129,7 @@ int main(void) aim_conn_addhandler(&aimsess, authconn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY, faimtest_authsvrready, 0); aim_send_login(&aimsess, authconn, screenname, password, &info); #endif + aim_conn_addhandler(&aimsess, authconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_DEBUGCONN_CONNECT, faimtest_debugconn_connect, 0); printf("faimtest: login sent\n"); while (keepgoing) { @@ -973,3 +975,19 @@ int faimtest_parse_connerr(struct aim_session_t *sess, struct command_rx_struct return 1; } + +int faimtest_debugconn_connect(struct aim_session_t *sess, struct command_rx_struct *command, ...) +{ + printf("faimtest: connecting to an aimdebugd!\n"); + + /* convert the authorizer connection to a BOS connection */ + command->conn->type = AIM_CONN_TYPE_BOS; + + aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_MSG, AIM_CB_MSG_INCOMING, faimtest_parse_incoming_im, 0); + + /* tell the aimddebugd we're ready */ + aim_debugconn_sendconnect(sess, command->conn); + + /* go right into main loop (don't open a BOS connection, etc) */ + return 1; +} -- 2.45.2