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