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