]> andersk Git - libfaim.git/blob - aim_login.c
44202567f1a6cbfe954e11b77bb3fd26deabd58e
[libfaim.git] / aim_login.c
1 /*
2  *  aim_login.c
3  *
4  *  This contains all the functions needed to actually login.
5  *
6  */
7
8 #include <faim/aim.h>
9
10 #include "md5.h"
11
12 static int aim_encode_password_md5(const char *password, const char *key, md5_byte_t *digest);
13
14 /*
15  * FIXME: Reimplement the TIS stuff.
16  */
17 #ifdef TIS_TELNET_PROXY
18 #include "tis_telnet_proxy.h"
19 #endif
20
21 faim_export int aim_sendconnack(struct aim_session_t *sess,
22                                 struct aim_conn_t *conn)
23 {
24   int curbyte=0;
25   
26   struct command_tx_struct *newpacket;
27
28   if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0001, conn, 4)))
29     return -1;
30
31   newpacket->lock = 1;
32   
33   curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000);
34   curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001);
35
36   newpacket->lock = 0;
37   return aim_tx_enqueue(sess, newpacket);
38 }
39
40 /*
41  * In AIM 3.5 protocol, the first stage of login is to request
42  * login from the Authorizer, passing it the screen name
43  * for verification.  If the name is invalid, a 0017/0003 
44  * is spit back, with the standard error contents.  If valid,
45  * a 0017/0007 comes back, which is the signal to send
46  * it the main login command (0017/0002).  
47  */
48 faim_export int aim_request_login(struct aim_session_t *sess,
49                                   struct aim_conn_t *conn, 
50                                   char *sn)
51 {
52   int curbyte=0;
53   
54   struct command_tx_struct *newpacket;
55
56   if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+2+2+strlen(sn))))
57     return -1;
58
59   newpacket->lock = 1;
60   
61   curbyte += aim_putsnac(newpacket->data+curbyte, 0x0017, 0x0006, 0x0000, 0x00010000);
62   curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x0001, strlen(sn), sn);
63
64   newpacket->lock = 0;
65   return aim_tx_enqueue(sess, newpacket);
66 }
67
68 /*
69  * send_login(int socket, char *sn, char *password)
70  *  
71  * This is the initial login request packet.
72  *
73  * The password is encoded before transmition, as per
74  * encode_password().  See that function for their
75  * stupid method of doing it.
76  *
77  */
78 faim_export int aim_send_login (struct aim_session_t *sess,
79                                 struct aim_conn_t *conn, 
80                                 char *sn, char *password, 
81                                 struct client_info_s *clientinfo,
82                                 char *key)
83 {
84   int curbyte=0;
85   md5_byte_t digest[16];
86   
87   struct command_tx_struct *newpacket;
88
89   if (!clientinfo || !sn || !password)
90     return -1;
91
92   if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 1152)))
93     return -1;
94
95   newpacket->lock = 1;
96
97   newpacket->hdr.oscar.type = 0x02;
98   
99   curbyte = aim_putsnac(newpacket->data+curbyte, 0x0017, 0x0002, 0x0000, 0x00010000);
100
101   curbyte+= aim_puttlv_str(newpacket->data+curbyte, 0x0001, strlen(sn), sn);
102   
103   aim_encode_password_md5(password, key, digest);
104   curbyte+= aim_puttlv_str(newpacket->data+curbyte, 0x0025, 16, (char *)digest);
105   
106   /* XXX is clientstring required by oscar? */
107   if (strlen(clientinfo->clientstring))
108     curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x0003, strlen(clientinfo->clientstring), clientinfo->clientstring);
109
110   curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0016, (unsigned short)clientinfo->major2);
111   curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0017, (unsigned short)clientinfo->major);
112   curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0018, (unsigned short)clientinfo->minor);
113   curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0019, (unsigned short)clientinfo->minor2);
114   curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x001a, (unsigned short)clientinfo->build);
115   
116   curbyte += aim_puttlv_32(newpacket->data+curbyte, 0x0014, clientinfo->unknown);
117   curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0009, 0x0015);
118
119   if (strlen(clientinfo->country))
120     curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x000e, strlen(clientinfo->country), clientinfo->country);
121   else
122     curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x000e, 2, "us");
123
124   if (strlen(clientinfo->lang))
125     curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x000f, strlen(clientinfo->lang), clientinfo->lang);
126   else
127     curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x000f, 2, "en");
128   
129   newpacket->commandlen = curbyte;
130
131   newpacket->lock = 0;
132   return aim_tx_enqueue(sess, newpacket);
133 }
134
135 static int aim_encode_password_md5(const char *password, const char *key, md5_byte_t *digest)
136 {
137   md5_state_t state;
138
139   md5_init(&state);     
140   md5_append(&state, (const md5_byte_t *)key, strlen(key));
141   md5_append(&state, (const md5_byte_t *)password, strlen(password));
142   md5_append(&state, (const md5_byte_t *)AIM_MD5_STRING, strlen(AIM_MD5_STRING));
143   md5_finish(&state, (md5_byte_t *)digest);
144
145   return 0;
146 }
147
148 /*
149  *  int encode_password(
150  *                      const char *password,
151  *                      char *encoded
152  *                      ); 
153  *
154  * This takes a const pointer to a (null terminated) string
155  * containing the unencoded password.  It also gets passed
156  * an already allocated buffer to store the encoded password.
157  * This buffer should be the exact length of the password without
158  * the null.  The encoded password buffer IS NOT NULL TERMINATED.
159  *
160  * The encoding_table seems to be a fixed set of values.  We'll
161  * hope it doesn't change over time!  
162  *
163  * NOTE: This is no longer used. Its here for historical reference.
164  *
165  */
166 #if 0
167 static int aim_encode_password(const char *password, unsigned char *encoded)
168 {
169   u_char encoding_table[] = {
170 #if 0 /* old v1 table */
171     0xf3, 0xb3, 0x6c, 0x99,
172     0x95, 0x3f, 0xac, 0xb6,
173     0xc5, 0xfa, 0x6b, 0x63,
174     0x69, 0x6c, 0xc3, 0x9f
175 #else /* v2.1 table, also works for ICQ */
176     0xf3, 0x26, 0x81, 0xc4,
177     0x39, 0x86, 0xdb, 0x92,
178     0x71, 0xa3, 0xb9, 0xe6,
179     0x53, 0x7a, 0x95, 0x7c
180 #endif
181   };
182
183   int i;
184   
185   for (i = 0; i < strlen(password); i++)
186       encoded[i] = (password[i] ^ encoding_table[i]);
187
188   return 0;
189 }
190 #endif
191
192 /*
193  * This is sent back as a general response to the login command.
194  * It can be either an error or a success, depending on the
195  * precense of certain TLVs.  
196  *
197  * The client should check the value of logininfo->errorcode. If
198  * its nonzero, there was an error.
199  *
200  */
201 faim_internal int aim_authparse(struct aim_session_t *sess, 
202                                 struct command_rx_struct *command)
203 {
204   struct aim_tlvlist_t *tlvlist;
205   int ret = 1;
206   char *sn;
207   rxcallback_t userfunc = NULL;
208
209   memset(&sess->logininfo, 0x00, sizeof(sess->logininfo));
210
211   /*
212    * Read block of TLVs.  All further data is derived
213    * from what is parsed here.
214    *
215    * For SNAC login, there's a 17/3 SNAC header in front.
216    *
217    */
218   tlvlist = aim_readtlvchain(command->data+10, command->commandlen-10);
219
220   /*
221    * No matter what, we should have a screen name.
222    */
223   sn = aim_gettlv_str(tlvlist, 0x0001, 1);
224   strncpy(sess->logininfo.screen_name, sn, strlen(sn));
225   free(sn);
226
227   /*
228    * Check for an error code.  If so, we should also
229    * have an error url.
230    */
231   if (aim_gettlv(tlvlist, 0x0008, 1)) {
232     struct aim_tlv_t *errtlv;
233     errtlv = aim_gettlv(tlvlist, 0x0008, 1);
234     sess->logininfo.errorcode = aimutil_get16(errtlv->value);
235     sess->logininfo.errorurl = aim_gettlv_str(tlvlist, 0x0004, 1);
236   }
237   /* 
238    * If we have both an IP number (0x0005) and a cookie (0x0006),
239    * then the login was successful.
240    */
241   else if (aim_gettlv(tlvlist, 0x0005, 1) && aim_gettlv(tlvlist, 0x0006, 1) 
242            /*aim_gettlv(tlvlist, 0x0006, 1)->length*/) {
243     struct aim_tlv_t *tmptlv;
244
245     /*
246      * IP address of BOS server.
247      */
248     sess->logininfo.BOSIP = aim_gettlv_str(tlvlist, 0x0005, 1);
249     
250     /*
251      * Authorization Cookie
252      */
253     tmptlv = aim_gettlv(tlvlist, 0x0006, 1);
254     memcpy(sess->logininfo.cookie, tmptlv->value, AIM_COOKIELEN);
255     
256     /*
257      * The email address attached to this account
258      *   Not available for ICQ logins.
259      */
260     if (aim_gettlv(tlvlist, 0x0011, 1))
261       sess->logininfo.email = aim_gettlv_str(tlvlist, 0x0011, 1);
262     
263     /*
264      * The registration status.  (Not real sure what it means.)
265      *   Not available for ICQ logins.
266      */
267     if ((tmptlv = aim_gettlv(tlvlist, 0x0013, 1)))
268       sess->logininfo.regstatus = aimutil_get16(tmptlv->value);
269       
270   }
271
272   userfunc = aim_callhandler(command->conn, 0x0017, 0x0003);
273
274   if (userfunc)
275     ret = userfunc(sess, command);
276
277   aim_freetlvchain(&tlvlist);
278
279   if (sess->logininfo.BOSIP) {
280     free(sess->logininfo.BOSIP);
281     sess->logininfo.BOSIP = NULL;
282   }
283   if (sess->logininfo.email) {
284     free(sess->logininfo.email);
285     sess->logininfo.email = NULL;
286   }
287   if (sess->logininfo.errorurl) {
288     free(sess->logininfo.errorurl);
289     sess->logininfo.errorurl = NULL;
290   }
291
292   return ret;
293 }
294
295 /*
296  * Middle handler for 0017/0007 SNACs.  Contains the auth key prefixed
297  * by only its length in a two byte word.
298  *
299  * Calls the client, which should then use the value to call aim_send_login.
300  *
301  */
302 faim_internal int aim_authkeyparse(struct aim_session_t *sess, struct command_rx_struct *command)
303 {
304   unsigned char *key;
305   int keylen;
306   int ret = 1;
307   rxcallback_t userfunc;
308
309   keylen = aimutil_get16(command->data+10);
310   if (!(key = malloc(keylen+1)))
311     return ret;
312   memcpy(key, command->data+12, keylen);
313   key[keylen] = '\0';
314   
315   if ((userfunc = aim_callhandler(command->conn, 0x0017, 0x0007)))
316     ret = userfunc(sess, command, (char *)key);
317
318   free(key);  
319
320   return ret;
321 }
322
323 /*
324  * Generate an authorization response.  
325  *
326  * You probably don't want this unless you're writing an AIM server.
327  *
328  */
329 faim_export unsigned long aim_sendauthresp(struct aim_session_t *sess, 
330                                            struct aim_conn_t *conn, 
331                                            char *sn, char *bosip, 
332                                            char *cookie, char *email, 
333                                            int regstatus)
334 {       
335   struct command_tx_struct *tx;
336   struct aim_tlvlist_t *tlvlist = NULL;
337
338   if (!(tx = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0004, conn, 1152)))
339     return -1;
340   
341   tx->lock = 1;
342
343   if (sn)
344     aim_addtlvtochain_str(&tlvlist, 0x0001, sn, strlen(sn));
345   else
346     aim_addtlvtochain_str(&tlvlist, 0x0001, sess->logininfo.screen_name, strlen(sess->logininfo.screen_name));
347
348   if (sess->logininfo.errorcode) {
349     aim_addtlvtochain16(&tlvlist, 0x0008, sess->logininfo.errorcode);
350     aim_addtlvtochain_str(&tlvlist, 0x0004, sess->logininfo.errorurl, strlen(sess->logininfo.errorurl));
351   } else {
352     aim_addtlvtochain_str(&tlvlist, 0x0005, bosip, strlen(bosip));
353     aim_addtlvtochain_str(&tlvlist, 0x0006, cookie, AIM_COOKIELEN);
354     aim_addtlvtochain_str(&tlvlist, 0x0011, email, strlen(email));
355     aim_addtlvtochain16(&tlvlist, 0x0013, (unsigned short)regstatus);
356   }
357
358   tx->commandlen = aim_writetlvchain(tx->data, tx->commandlen, &tlvlist);
359   tx->lock = 0;
360   return aim_tx_enqueue(sess, tx);
361 }
362
363 /*
364  * Generate a random cookie.  (Non-client use only)
365  */
366 faim_export int aim_gencookie(unsigned char *buf)
367 {
368   int i;
369
370   srand(time(NULL));
371
372   for (i=0; i < AIM_COOKIELEN; i++)
373     buf[i] = 1+(int) (256.0*rand()/(RAND_MAX+0.0));
374
375   return i;
376 }
377
378 /*
379  * Send Server Ready.  (Non-client)
380  */
381 faim_export int aim_sendserverready(struct aim_session_t *sess, struct aim_conn_t *conn)
382 {
383   struct command_tx_struct *tx;
384   int i = 0;
385
386   if (!(tx = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+0x22)))
387     return -1;
388
389   tx->lock = 1;
390
391   i += aim_putsnac(tx->data, 0x0001, 0x0003, 0x0000, sess->snac_nextid++);
392   
393   i += aimutil_put16(tx->data+i, 0x0001);  
394   i += aimutil_put16(tx->data+i, 0x0002);
395   i += aimutil_put16(tx->data+i, 0x0003);
396   i += aimutil_put16(tx->data+i, 0x0004);
397   i += aimutil_put16(tx->data+i, 0x0006);
398   i += aimutil_put16(tx->data+i, 0x0008);
399   i += aimutil_put16(tx->data+i, 0x0009);
400   i += aimutil_put16(tx->data+i, 0x000a);
401   i += aimutil_put16(tx->data+i, 0x000b);
402   i += aimutil_put16(tx->data+i, 0x000c);
403   i += aimutil_put16(tx->data+i, 0x0013);
404   i += aimutil_put16(tx->data+i, 0x0015);
405
406   tx->commandlen = i;
407   tx->lock = 0;
408   return aim_tx_enqueue(sess, tx);
409 }
410
411
412 /* 
413  * Send service redirect.  (Non-Client)
414  */
415 faim_export unsigned long aim_sendredirect(struct aim_session_t *sess, 
416                                            struct aim_conn_t *conn, 
417                                            unsigned short servid, 
418                                            char *ip,
419                                            char *cookie)
420 {       
421   struct command_tx_struct *tx;
422   struct aim_tlvlist_t *tlvlist = NULL;
423   int i = 0;
424
425   if (!(tx = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 1152)))
426     return -1;
427
428   tx->lock = 1;
429
430   i += aim_putsnac(tx->data+i, 0x0001, 0x0005, 0x0000, 0x00000000);
431   
432   aim_addtlvtochain16(&tlvlist, 0x000d, servid);
433   aim_addtlvtochain_str(&tlvlist, 0x0005, ip, strlen(ip));
434   aim_addtlvtochain_str(&tlvlist, 0x0006, cookie, AIM_COOKIELEN);
435
436   tx->commandlen = aim_writetlvchain(tx->data+i, tx->commandlen-i, &tlvlist)+i;
437   aim_freetlvchain(&tlvlist);
438
439   tx->lock = 0;
440   return aim_tx_enqueue(sess, tx);
441 }
This page took 0.615975 seconds and 3 git commands to generate.