]> andersk Git - libfaim.git/blob - src/login.c
784ac1b8840122d9844443af08be6bcb91c6d704
[libfaim.git] / src / login.c
1 /*
2  *  aim_login.c
3  *
4  *  This contains all the functions needed to actually login.
5  *
6  */
7
8 #define FAIM_INTERNAL
9 #include <aim.h>
10
11 #include "md5.h"
12
13 static int aim_encode_password(const char *password, unsigned char *encoded);
14
15 faim_export int aim_sendflapver(aim_session_t *sess, aim_conn_t *conn)
16 {
17         aim_frame_t *fr;
18
19         if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x01, 4)))
20                 return -ENOMEM;
21
22         aimbs_put32(&fr->data, 0x00000001);
23
24         aim_tx_enqueue(sess, fr);
25
26         return 0;
27 }
28
29 /*
30  * In AIM 3.5 protocol, the first stage of login is to request login from the 
31  * Authorizer, passing it the screen name for verification.  If the name is 
32  * invalid, a 0017/0003 is spit back, with the standard error contents.  If 
33  * valid, a 0017/0007 comes back, which is the signal to send it the main 
34  * login command (0017/0002). 
35  *
36  * XXX make ICQ logins work again. 
37  */
38 faim_export int aim_request_login(aim_session_t *sess, aim_conn_t *conn, const char *sn)
39 {
40         aim_frame_t *fr;
41         aim_snacid_t snacid;
42         aim_tlvlist_t *tl = NULL;
43         
44         if (!sess || !conn || !sn)
45                 return -EINVAL;
46
47         sess->flags |= AIM_SESS_FLAGS_SNACLOGIN;
48
49         aim_sendflapver(sess, conn);
50
51         if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+2+2+strlen(sn))))
52                 return -ENOMEM;
53
54         snacid = aim_cachesnac(sess, 0x0017, 0x0006, 0x0000, NULL, 0);
55         aim_putsnac(&fr->data, 0x0017, 0x0006, 0x0000, snacid);
56
57         aim_addtlvtochain_raw(&tl, 0x0001, strlen(sn), sn);
58         aim_writetlvchain(&fr->data, &tl);
59         aim_freetlvchain(&tl);
60
61         aim_tx_enqueue(sess, fr);
62
63         return 0;
64 }
65
66 /*
67  * send_login(int socket, char *sn, char *password)
68  *  
69  * This is the initial login request packet.
70  *
71  * NOTE!! If you want/need to make use of the aim_sendmemblock() function,
72  * then the client information you send here must exactly match the
73  * executable that you're pulling the data from.
74  *
75  * Latest WinAIM:
76  *   clientstring = "AOL Instant Messenger (SM), version 4.3.2188/WIN32"
77  *   major2 = 0x0109
78  *   major = 0x0400
79  *   minor = 0x0003
80  *   minor2 = 0x0000
81  *   build = 0x088c
82  *   unknown = 0x00000086
83  *   lang = "en"
84  *   country = "us"
85  *   unknown4a = 0x01
86  *
87  * Latest WinAIM that libfaim can emulate without server-side buddylists:
88  *   clientstring = "AOL Instant Messenger (SM), version 4.1.2010/WIN32"
89  *   major2 = 0x0004
90  *   major  = 0x0004
91  *   minor  = 0x0001
92  *   minor2 = 0x0000
93  *   build  = 0x07da
94  *   unknown= 0x0000004b
95  *
96  * WinAIM 3.5.1670:
97  *   clientstring = "AOL Instant Messenger (SM), version 3.5.1670/WIN32"
98  *   major2 = 0x0004
99  *   major =  0x0003
100  *   minor =  0x0005
101  *   minor2 = 0x0000
102  *   build =  0x0686
103  *   unknown =0x0000002a
104  *
105  * Java AIM 1.1.19:
106  *   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"
107  *   major2 = 0x0001
108  *   major  = 0x0001
109  *   minor  = 0x0001
110  *   minor2 = (not sent)
111  *   build  = 0x0013
112  *   unknown= (not sent)
113  *   
114  * AIM for Linux 1.1.112:
115  *   clientstring = "AOL Instant Messenger (SM)"
116  *   major2 = 0x1d09
117  *   major  = 0x0001
118  *   minor  = 0x0001
119  *   minor2 = 0x0001
120  *   build  = 0x0070
121  *   unknown= 0x0000008b
122  *   serverstore = 0x01
123  *
124  */
125 faim_export int aim_send_login(aim_session_t *sess, aim_conn_t *conn, const char *sn, const char *password, struct client_info_s *clientinfo, const char *key)
126 {
127         aim_frame_t *fr;
128         aim_tlvlist_t *tl = NULL;
129
130         if (!clientinfo || !sn || !password)
131                 return -EINVAL;
132
133         if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152)))
134                 return -ENOMEM;
135
136         if (sess->flags & AIM_SESS_FLAGS_XORLOGIN) {
137                 fr->hdr.flap.type = 0x01;
138
139                 /* Use very specific version numbers to further indicate hack */
140                 clientinfo->major2 = 0x010a;
141                 clientinfo->major = 0x0004;
142                 clientinfo->minor = 0x003c;
143                 clientinfo->minor2 = 0x0001;
144                 clientinfo->build = 0x0cce;
145                 clientinfo->unknown = 0x00000055;
146         }
147
148         if (sess->flags & AIM_SESS_FLAGS_SNACLOGIN)
149                 aim_putsnac(&fr->data, 0x0017, 0x0002, 0x0000, 0x00010000);
150         else
151                 aimbs_put32(&fr->data, 0x00000001);
152
153         aim_addtlvtochain_raw(&tl, 0x0001, strlen(sn), sn);
154
155         if (sess->flags & AIM_SESS_FLAGS_SNACLOGIN) {
156                 fu8_t digest[16];
157
158                 aim_encode_password_md5(password, key, digest);
159                 aim_addtlvtochain_raw(&tl, 0x0025, 16, digest);
160         } else { 
161                 char *password_encoded;
162
163                 password_encoded = (char *) malloc(strlen(password));
164                 aim_encode_password(password, password_encoded);
165                 aim_addtlvtochain_raw(&tl, 0x0002, strlen(password), password_encoded);
166                 free(password_encoded);
167         }
168
169         aim_addtlvtochain_raw(&tl, 0x0003, strlen(clientinfo->clientstring), clientinfo->clientstring);
170
171         aim_addtlvtochain16(&tl, 0x0016, (fu16_t)clientinfo->major2);
172         aim_addtlvtochain16(&tl, 0x0017, (fu16_t)clientinfo->major);
173         aim_addtlvtochain16(&tl, 0x0018, (fu16_t)clientinfo->minor);
174         aim_addtlvtochain16(&tl, 0x0019, (fu16_t)clientinfo->minor2);
175         aim_addtlvtochain16(&tl, 0x001a, (fu16_t)clientinfo->build);
176
177         aim_addtlvtochain_raw(&tl, 0x000e, strlen(clientinfo->country), clientinfo->country);
178         aim_addtlvtochain_raw(&tl, 0x000f, strlen(clientinfo->lang), clientinfo->lang);
179
180         if (sess->flags & AIM_SESS_FLAGS_SNACLOGIN)
181                 aim_addtlvtochain16(&tl, 0x0009, 0x0015);
182
183         aim_writetlvchain(&fr->data, &tl);
184
185         aim_freetlvchain(&tl);
186         
187         aim_tx_enqueue(sess, fr);
188
189         return 0;
190 }
191
192 faim_export int aim_encode_password_md5(const char *password, const char *key, fu8_t *digest)
193 {
194         md5_state_t state;
195
196         md5_init(&state);       
197         md5_append(&state, (const md5_byte_t *)key, strlen(key));
198         md5_append(&state, (const md5_byte_t *)password, strlen(password));
199         md5_append(&state, (const md5_byte_t *)AIM_MD5_STRING, strlen(AIM_MD5_STRING));
200         md5_finish(&state, (md5_byte_t *)digest);
201
202         return 0;
203 }
204
205 /**
206  * aim_encode_password - Encode a password using old XOR method
207  * @password: incoming password
208  * @encoded: buffer to put encoded password
209  *
210  * This takes a const pointer to a (null terminated) string
211  * containing the unencoded password.  It also gets passed
212  * an already allocated buffer to store the encoded password.
213  * This buffer should be the exact length of the password without
214  * the null.  The encoded password buffer /is not %NULL terminated/.
215  *
216  * The encoding_table seems to be a fixed set of values.  We'll
217  * hope it doesn't change over time!  
218  *
219  * This is only used for the XOR method, not the better MD5 method.
220  *
221  */
222 static int aim_encode_password(const char *password, fu8_t *encoded)
223 {
224         fu8_t encoding_table[] = {
225 #if 0 /* old v1 table */
226                 0xf3, 0xb3, 0x6c, 0x99,
227                 0x95, 0x3f, 0xac, 0xb6,
228                 0xc5, 0xfa, 0x6b, 0x63,
229                 0x69, 0x6c, 0xc3, 0x9f
230 #else /* v2.1 table, also works for ICQ */
231                 0xf3, 0x26, 0x81, 0xc4,
232                 0x39, 0x86, 0xdb, 0x92,
233                 0x71, 0xa3, 0xb9, 0xe6,
234                 0x53, 0x7a, 0x95, 0x7c
235 #endif
236         };
237         int i;
238
239         for (i = 0; i < strlen(password); i++)
240                 encoded[i] = (password[i] ^ encoding_table[i]);
241
242         return 0;
243 }
244
245 /*
246  * Generate an authorization response.  
247  *
248  * You probably don't want this unless you're writing an AIM server. Which
249  * I hope you're not doing.  Because it's far more difficult than it looks.
250  *
251  */
252 faim_export int aim_sendauthresp(aim_session_t *sess, aim_conn_t *conn, const char *sn, int errorcode, const char *errorurl, const char *bosip, const char *cookie, const char *email, int regstatus)
253 {       
254         aim_tlvlist_t *tlvlist = NULL;
255         aim_frame_t *fr;
256
257         if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x04, 1152)))
258                 return -ENOMEM;
259
260         if (sn)
261                 aim_addtlvtochain_raw(&tlvlist, 0x0001, strlen(sn), sn);
262         else
263                 aim_addtlvtochain_raw(&tlvlist, 0x0001, strlen(sess->sn), sess->sn);
264
265         if (errorcode) {
266                 aim_addtlvtochain16(&tlvlist, 0x0008, errorcode);
267                 aim_addtlvtochain_raw(&tlvlist, 0x0004, strlen(errorurl), errorurl);
268         } else {
269                 aim_addtlvtochain_raw(&tlvlist, 0x0005, strlen(bosip), bosip);
270                 aim_addtlvtochain_raw(&tlvlist, 0x0006, AIM_COOKIELEN, cookie);
271                 aim_addtlvtochain_raw(&tlvlist, 0x0011, strlen(email), email);
272                 aim_addtlvtochain16(&tlvlist, 0x0013, (fu16_t)regstatus);
273         }
274
275         aim_writetlvchain(&fr->data, &tlvlist);
276         aim_freetlvchain(&tlvlist);
277
278         aim_tx_enqueue(sess, fr);
279
280         return 0;
281 }
282
283 /*
284  * Generate a random cookie.  (Non-client use only)
285  */
286 faim_export int aim_gencookie(fu8_t *buf)
287 {
288         int i;
289
290         srand(time(NULL));
291
292         for (i = 0; i < AIM_COOKIELEN; i++)
293                 buf[i] = 1+(int) (256.0*rand()/(RAND_MAX+0.0));
294
295         return i;
296 }
297
298 /*
299  * Send Server Ready.  (Non-client)
300  */
301 faim_export int aim_sendserverready(aim_session_t *sess, aim_conn_t *conn)
302 {
303         aim_frame_t *fr;
304         aim_snacid_t snacid;
305
306         if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+0x22)))
307                 return -ENOMEM;
308
309         snacid = aim_cachesnac(sess, 0x0001, 0x0003, 0x0000, NULL, 0);
310
311         aim_putsnac(&fr->data, 0x0001, 0x0003, 0x0000, snacid);
312         aimbs_put16(&fr->data, 0x0001);
313         aimbs_put16(&fr->data, 0x0002);
314         aimbs_put16(&fr->data, 0x0003);
315         aimbs_put16(&fr->data, 0x0004);
316         aimbs_put16(&fr->data, 0x0006);
317         aimbs_put16(&fr->data, 0x0008);
318         aimbs_put16(&fr->data, 0x0009);
319         aimbs_put16(&fr->data, 0x000a);
320         aimbs_put16(&fr->data, 0x000b);
321         aimbs_put16(&fr->data, 0x000c);
322         aimbs_put16(&fr->data, 0x0013);
323         aimbs_put16(&fr->data, 0x0015);
324
325         aim_tx_enqueue(sess, fr);
326
327         return 0;
328 }
329
330
331 /* 
332  * Send service redirect.  (Non-Client)
333  */
334 faim_export int aim_sendredirect(aim_session_t *sess, aim_conn_t *conn, fu16_t servid, const char *ip, const char *cookie)
335 {       
336         aim_tlvlist_t *tlvlist = NULL;
337         aim_frame_t *fr;
338         aim_snacid_t snacid;
339
340         if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152)))
341                 return -ENOMEM;
342
343         snacid = aim_cachesnac(sess, 0x0001, 0x0005, 0x0000, NULL, 0);
344         aim_putsnac(&fr->data, 0x0001, 0x0005, 0x0000, snacid);
345
346         aim_addtlvtochain16(&tlvlist, 0x000d, servid);
347         aim_addtlvtochain_raw(&tlvlist, 0x0005, strlen(ip), ip);
348         aim_addtlvtochain_raw(&tlvlist, 0x0006, AIM_COOKIELEN, cookie);
349
350         aim_writetlvchain(&fr->data, &tlvlist);
351         aim_freetlvchain(&tlvlist);
352
353         aim_tx_enqueue(sess, fr);
354
355         return 0;
356 }
357
358
359 static int hostonline(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
360 {
361         aim_rxcallback_t userfunc;
362         int ret = 0;
363         fu16_t *families;
364         int famcount;
365
366         if (!(families = malloc(aim_bstream_empty(bs))))
367                 return 0;
368
369         for (famcount = 0; aim_bstream_empty(bs); famcount++)
370                 families[famcount] = aimbs_get16(bs);
371
372         if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
373                 ret = userfunc(sess, rx, famcount, families);
374
375         free(families);
376
377         return ret; 
378 }
379
380 static int redirect(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
381 {
382         int serviceid;
383         fu8_t *cookie;
384         char *ip;
385         aim_rxcallback_t userfunc;
386         aim_tlvlist_t *tlvlist;
387         char *chathack = NULL;
388         int chathackex = 0;
389         int ret = 0;
390
391         tlvlist = aim_readtlvchain(bs);
392
393         if (!aim_gettlv(tlvlist, 0x000d, 1) ||
394                         !aim_gettlv(tlvlist, 0x0005, 1) ||
395                         !aim_gettlv(tlvlist, 0x0006, 1)) {
396                 aim_freetlvchain(&tlvlist);
397                 return 0;
398         }
399
400         serviceid = aim_gettlv16(tlvlist, 0x000d, 1);
401         ip = aim_gettlv_str(tlvlist, 0x0005, 1);
402         cookie = aim_gettlv_str(tlvlist, 0x0006, 1);
403
404         /*
405          * Chat hack.
406          */
407         if ((serviceid == AIM_CONN_TYPE_CHAT) && sess->pendingjoin) {
408                 chathack = sess->pendingjoin;
409                 chathackex = sess->pendingjoinexchange;
410                 sess->pendingjoin = NULL;
411                 sess->pendingjoinexchange = 0;
412         }
413
414         if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
415                 ret = userfunc(sess, rx, serviceid, ip, cookie, chathack, chathackex);
416
417         free(ip);
418         free(cookie);
419         free(chathack);
420
421         aim_freetlvchain(&tlvlist);
422
423         return ret;
424 }
425
426 /*
427  * The Rate Limiting System, An Abridged Guide to Nonsense.
428  *
429  * OSCAR defines several 'rate classes'.  Each class has seperate
430  * rate limiting properties (limit level, alert level, disconnect
431  * level, etc), and a set of SNAC family/type pairs associated with
432  * it.  The rate classes, their limiting properties, and the definitions
433  * of which SNACs are belong to which class, are defined in the
434  * Rate Response packet at login to each host.  
435  *
436  * Logically, all rate offenses within one class count against further
437  * offenses for other SNACs in the same class (ie, sending messages
438  * too fast will limit the number of user info requests you can send,
439  * since those two SNACs are in the same rate class).
440  *
441  * Since the rate classes are defined dynamically at login, the values
442  * below may change. But they seem to be fairly constant.
443  *
444  * Currently, BOS defines five rate classes, with the commonly used
445  * members as follows...
446  *
447  *  Rate class 0x0001:
448  *      - Everything thats not in any of the other classes
449  *
450  *  Rate class 0x0002:
451  *      - Buddy list add/remove
452  *      - Permit list add/remove
453  *      - Deny list add/remove
454  *
455  *  Rate class 0x0003:
456  *      - User information requests
457  *      - Outgoing ICBMs
458  *
459  *  Rate class 0x0004:
460  *      - A few unknowns: 2/9, 2/b, and f/2
461  *
462  *  Rate class 0x0005:
463  *      - Chat room create
464  *      - Outgoing chat ICBMs
465  *
466  * The only other thing of note is that class 5 (chat) has slightly looser
467  * limiting properties than class 3 (normal messages).  But thats just a 
468  * small bit of trivia for you.
469  *
470  * The last thing that needs to be learned about the rate limiting
471  * system is how the actual numbers relate to the passing of time.  This
472  * seems to be a big mystery.
473  * 
474  */
475
476 /* XXX parse this */
477 static int rateresp(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
478 {
479         aim_rxcallback_t userfunc;
480
481         if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
482                 return userfunc(sess, rx);
483
484         return 0;
485 }
486
487 static int ratechange(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
488 {
489         aim_rxcallback_t userfunc;
490         fu16_t code, rateclass;
491         fu32_t currentavg, maxavg, windowsize, clear, alert, limit, disconnect;
492
493         code = aimbs_get16(bs);
494         rateclass = aimbs_get16(bs);
495         
496         windowsize = aimbs_get32(bs);
497         clear = aimbs_get32(bs);
498         alert = aimbs_get32(bs);
499         limit = aimbs_get32(bs);
500         disconnect = aimbs_get32(bs);
501         currentavg = aimbs_get32(bs);
502         maxavg = aimbs_get32(bs);
503
504         if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
505                 return userfunc(sess, rx, code, rateclass, windowsize, clear, alert, limit, disconnect, currentavg, maxavg);
506
507         return 0;
508 }
509
510 /* XXX parse this */
511 static int selfinfo(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
512 {
513         aim_rxcallback_t userfunc;
514
515         if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
516                 return userfunc(sess, rx);
517
518         return 0;
519 }
520
521 static int evilnotify(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
522 {
523         aim_rxcallback_t userfunc;
524         fu16_t newevil;
525         struct aim_userinfo_s userinfo;
526
527         memset(&userinfo, 0, sizeof(struct aim_userinfo_s));
528         
529         newevil = aimbs_get16(bs);
530
531         if (aim_bstream_empty(bs))
532                 aim_extractuserinfo(sess, bs, &userinfo);
533
534         if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
535                 return userfunc(sess, rx, newevil, &userinfo);
536
537         return 0;
538 }
539
540 static int motd(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
541 {
542         aim_rxcallback_t userfunc;
543         char *msg = NULL;
544         int ret = 0;
545         aim_tlvlist_t *tlvlist;
546         fu16_t id;
547
548         /*
549          * Code.
550          *
551          * Valid values:
552          *   1 Mandatory upgrade
553          *   2 Advisory upgrade
554          *   3 System bulletin
555          *   4 Nothing's wrong ("top o the world" -- normal)
556          *
557          */
558         id = aimbs_get16(bs);
559
560         /* 
561          * TLVs follow 
562          */
563         tlvlist = aim_readtlvchain(bs);
564
565         msg = aim_gettlv_str(tlvlist, 0x000b, 1);
566
567         if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
568                 ret = userfunc(sess, rx, id, msg);
569
570         free(msg);
571
572         aim_freetlvchain(&tlvlist);
573
574         return ret;
575 }
576
577 static int hostversions(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
578 {
579         aim_rxcallback_t userfunc;
580         int vercount;
581         fu8_t *versions;
582
583         vercount = aim_bstream_empty(bs)/4;
584         versions = aimbs_getraw(bs, aim_bstream_empty(bs));
585
586         if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
587                 return userfunc(sess, rx, vercount, versions);
588
589         free(versions);
590
591         return 0;
592 }
593
594 /*
595  * Starting this past week (26 Mar 2001, say), AOL has started sending
596  * this nice little extra SNAC.  AFAIK, it has never been used until now.
597  *
598  * The request contains eight bytes.  The first four are an offset, the
599  * second four are a length.
600  *
601  * The offset is an offset into aim.exe when it is mapped during execution
602  * on Win32.  So far, AOL has only been requesting bytes in static regions
603  * of memory.  (I won't put it past them to start requesting data in
604  * less static regions -- regions that are initialized at run time, but still
605  * before the client recieves this request.)
606  *
607  * When the client recieves the request, it adds it to the current ds
608  * (0x00400000) and dereferences it, copying the data into a buffer which
609  * it then runs directly through the MD5 hasher.  The 16 byte output of
610  * the hash is then sent back to the server.
611  *
612  * If the client does not send any data back, or the data does not match
613  * the data that the specific client should have, the client will get the
614  * following message from "AOL Instant Messenger":
615  *    "You have been disconnected from the AOL Instant Message Service (SM) 
616  *     for accessing the AOL network using unauthorized software.  You can
617  *     download a FREE, fully featured, and authorized client, here 
618  *     http://www.aol.com/aim/download2.html"
619  * The connection is then closed, recieving disconnect code 1, URL
620  * http://www.aim.aol.com/errors/USER_LOGGED_OFF_NEW_LOGIN.html.  
621  *
622  * Note, however, that numerous inconsistencies can cause the above error, 
623  * not just sending back a bad hash.  Do not immediatly suspect this code
624  * if you get disconnected.  AOL and the open/free software community have
625  * played this game for a couple years now, generating the above message
626  * on numerous ocassions.
627  *
628  * Anyway, neener.  We win again.
629  *
630  */
631 static int memrequest(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
632 {
633         aim_rxcallback_t userfunc;
634         fu32_t offset, len;
635         aim_tlvlist_t *list;
636         char *modname;
637
638         offset = aimbs_get32(bs);
639         len = aimbs_get32(bs);
640         list = aim_readtlvchain(bs);
641
642         modname = aim_gettlv_str(list, 0x0001, 1);
643
644         faimdprintf(sess, 1, "data at 0x%08lx (%d bytes) of requested\n", offset, len, modname ? modname : "aim.exe");
645
646         if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype)))
647                 return userfunc(sess, rx, offset, len, modname);
648
649         free(modname);
650         aim_freetlvchain(&list);
651
652         return 0;
653 }
654
655 #if 0
656 static void dumpbox(aim_session_t *sess, unsigned char *buf, int len)
657 {
658         int i;
659
660         if (!sess || !buf || !len)
661                 return;
662
663         faimdprintf(sess, 1, "\nDump of %d bytes at %p:", len, buf);
664
665         for (i = 0; i < len; i++) {
666                 if ((i % 8) == 0)
667                         faimdprintf(sess, 1, "\n\t");
668
669                 faimdprintf(sess, 1, "0x%2x ", buf[i]);
670         }
671
672         faimdprintf(sess, 1, "\n\n");
673
674         return;
675 }
676 #endif
677
678 faim_export int aim_sendmemblock(aim_session_t *sess, aim_conn_t *conn, fu32_t offset, fu32_t len, const fu8_t *buf, fu8_t flag)
679 {
680         aim_frame_t *fr;
681         aim_snacid_t snacid;
682
683         if (!sess || !conn)
684                 return -EINVAL;
685
686         if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+2+16)))
687                 return -ENOMEM;
688
689         snacid = aim_cachesnac(sess, 0x0001, 0x0020, 0x0000, NULL, 0);
690
691         aim_putsnac(&fr->data, 0x0001, 0x0020, 0x0000, snacid);
692         aimbs_put16(&fr->data, 0x0010); /* md5 is always 16 bytes */
693
694         if ((flag == AIM_SENDMEMBLOCK_FLAG_ISHASH) && buf && (len == 0x10)) { /* we're getting a hash */
695
696                 aimbs_putraw(&fr->data, buf, 0x10); 
697
698         } else if (buf && (len > 0)) { /* use input buffer */
699                 md5_state_t state;
700                 md5_byte_t digest[0x10];
701
702                 md5_init(&state);       
703                 md5_append(&state, (const md5_byte_t *)buf, len);
704                 md5_finish(&state, digest);
705
706                 aimbs_putraw(&fr->data, (fu8_t *)digest, 0x10);
707
708         } else if (len == 0) { /* no length, just hash NULL (buf is optional) */
709                 md5_state_t state;
710                 fu8_t nil = '\0';
711                 md5_byte_t digest[0x10];
712
713                 /*
714                  * These MD5 routines are stupid in that you have to have
715                  * at least one append.  So thats why this doesn't look 
716                  * real logical.
717                  */
718                 md5_init(&state);
719                 md5_append(&state, (const md5_byte_t *)&nil, 0);
720                 md5_finish(&state, digest);
721
722                 aimbs_putraw(&fr->data, (fu8_t *)digest, 0x10);
723
724         } else {
725
726                 /* 
727                  * This data is correct for AIM 3.5.1670.
728                  *
729                  * Using these blocks is as close to "legal" as you can get
730                  * without using an AIM binary.
731                  *
732                  */
733                 if ((offset == 0x03ffffff) && (len == 0x03ffffff)) {
734
735 #if 1 /* with "AnrbnrAqhfzcd" */
736                         aimbs_put32(&fr->data, 0x44a95d26);
737                         aimbs_put32(&fr->data, 0xd2490423);
738                         aimbs_put32(&fr->data, 0x93b8821f);
739                         aimbs_put32(&fr->data, 0x51c54b01);
740 #else /* no filename */
741                         aimbs_put32(&fr->data, 0x1df8cbae);
742                         aimbs_put32(&fr->data, 0x5523b839);
743                         aimbs_put32(&fr->data, 0xa0e10db3);
744                         aimbs_put32(&fr->data, 0xa46d3b39);
745 #endif
746
747                 } else if ((offset == 0x00001000) && (len == 0x00000000)) {
748
749                         aimbs_put32(&fr->data, 0xd41d8cd9);
750                         aimbs_put32(&fr->data, 0x8f00b204);
751                         aimbs_put32(&fr->data, 0xe9800998);
752                         aimbs_put32(&fr->data, 0xecf8427e);
753
754                 } else
755                         faimdprintf(sess, 0, "sendmemblock: WARNING: unknown hash request\n");
756
757         }
758
759         aim_tx_enqueue(sess, fr);
760
761         return 0;
762 }
763
764 static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
765 {
766
767         if (snac->subtype == 0x0003)
768                 return hostonline(sess, mod, rx, snac, bs);
769         else if (snac->subtype == 0x0005)
770                 return redirect(sess, mod, rx, snac, bs);
771         else if (snac->subtype == 0x0007)
772                 return rateresp(sess, mod, rx, snac, bs);
773         else if (snac->subtype == 0x000a)
774                 return ratechange(sess, mod, rx, snac, bs);
775         else if (snac->subtype == 0x000f)
776                 return selfinfo(sess, mod, rx, snac, bs);
777         else if (snac->subtype == 0x0010)
778                 return evilnotify(sess, mod, rx, snac, bs);
779         else if (snac->subtype == 0x0013)
780                 return motd(sess, mod, rx, snac, bs);
781         else if (snac->subtype == 0x0018)
782                 return hostversions(sess, mod, rx, snac, bs);
783         else if (snac->subtype == 0x001f)
784                 return memrequest(sess, mod, rx, snac, bs);
785
786         return 0;
787 }
788
789 faim_internal int general_modfirst(aim_session_t *sess, aim_module_t *mod)
790 {
791
792         mod->family = 0x0001;
793         mod->version = 0x0000;
794         mod->flags = 0;
795         strncpy(mod->name, "general", sizeof(mod->name));
796         mod->snachandler = snachandler;
797
798         return 0;
799 }
800
This page took 0.08432 seconds and 3 git commands to generate.