]> andersk Git - libfaim.git/blob - aim_login.c
Forgot this.
[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(AIM_FRAMETYPE_OSCAR, 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(AIM_FRAMETYPE_OSCAR, 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(AIM_FRAMETYPE_OSCAR, 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->hdr.oscar.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   aim_encode_password(password, password_encoded);
165   curbyte += aimutil_putstr(newpacket->data+curbyte, password_encoded, strlen(password));
166   free(password_encoded);
167   
168   if (strlen(clientinfo->clientstring)) {
169     curbyte += aimutil_put16(newpacket->data+curbyte, 0x0003);
170     curbyte += aimutil_put16(newpacket->data+curbyte, strlen(clientinfo->clientstring));
171     curbyte += aimutil_putstr(newpacket->data+curbyte, clientinfo->clientstring, strlen(clientinfo->clientstring));
172   }
173   curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0016, /*0x010a*/ 0x0004);
174   curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0017, clientinfo->major /*0x0001*/);
175   curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0018, clientinfo->minor /*0x0001*/);
176   curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0019, 0x0001);
177   curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x001a, clientinfo->build /*0x0013*/);
178
179   curbyte += aim_puttlv_32(newpacket->data+curbyte, 0x0014, 0x00000055);
180
181   if (strlen(clientinfo->country)) {
182     curbyte += aimutil_put16(newpacket->data+curbyte, 0x000e);
183     curbyte += aimutil_put16(newpacket->data+curbyte, strlen(clientinfo->country));
184     curbyte += aimutil_putstr(newpacket->data+curbyte, clientinfo->country, strlen(clientinfo->country));
185   }
186   if (strlen(clientinfo->lang)) {
187     curbyte += aimutil_put16(newpacket->data+curbyte, 0x000f);
188     curbyte += aimutil_put16(newpacket->data+curbyte, strlen(clientinfo->lang));
189     curbyte += aimutil_putstr(newpacket->data+curbyte, clientinfo->lang, strlen(clientinfo->lang));
190   }
191
192 #endif
193
194   newpacket->lock = 0;
195   return aim_tx_enqueue(sess, newpacket);
196 }
197
198 /*
199  *  int encode_password(
200  *                      const char *password,
201  *                      char *encoded
202  *                      ); 
203  *
204  * This takes a const pointer to a (null terminated) string
205  * containing the unencoded password.  It also gets passed
206  * an already allocated buffer to store the encoded password.
207  * This buffer should be the exact length of the password without
208  * the null.  The encoded password buffer IS NOT NULL TERMINATED.
209  *
210  * The encoding_table seems to be a fixed set of values.  We'll
211  * hope it doesn't change over time!  
212  *
213  */
214 int aim_encode_password(const char *password, u_char *encoded)
215 {
216   u_char encoding_table[] = {
217 #if 0 /* old v1 table */
218     0xf3, 0xb3, 0x6c, 0x99,
219     0x95, 0x3f, 0xac, 0xb6,
220     0xc5, 0xfa, 0x6b, 0x63,
221     0x69, 0x6c, 0xc3, 0x9f
222 #else /* v2.1 table, also works for ICQ */
223     0xf3, 0x26, 0x81, 0xc4,
224     0x39, 0x86, 0xdb, 0x92,
225     0x71, 0xa3, 0xb9, 0xe6,
226     0x53, 0x7a, 0x95, 0x7c
227 #endif
228   };
229
230   int i;
231   
232   for (i = 0; i < strlen(password); i++)
233       encoded[i] = (password[i] ^ encoding_table[i]);
234
235   return 0;
236 }
237
238 /*
239  * This is sent back as a general response to the login command.
240  * It can be either an error or a success, depending on the
241  * precense of certain TLVs.  
242  *
243  * The client should check the value of logininfo->errorcode. If
244  * its nonzero, there was an error.
245  *
246  */
247 int aim_authparse(struct aim_session_t *sess, 
248                   struct command_rx_struct *command)
249 {
250   struct aim_tlvlist_t *tlvlist;
251   int ret = 1;
252   char *sn;
253   rxcallback_t userfunc = NULL;
254
255   memset(&sess->logininfo, 0x00, sizeof(sess->logininfo));
256
257   /*
258    * Read block of TLVs.  All further data is derived
259    * from what is parsed here.
260    */
261 #ifdef SNACLOGIN
262   tlvlist = aim_readtlvchain(command->data+10, command->commandlen-10);
263 #else
264   tlvlist = aim_readtlvchain(command->data, command->commandlen);
265 #endif
266   /*
267    * No matter what, we should have a screen name.
268    */
269   sn = aim_gettlv_str(tlvlist, 0x0001, 1);
270   memcpy(sess->logininfo.screen_name, sn, strlen(sn));
271   sn[(strlen(sn))] = '\0';
272   
273   /*
274    * Check for an error code.  If so, we should also
275    * have an error url.
276    */
277   if (aim_gettlv(tlvlist, 0x0008, 1)) {
278     struct aim_tlv_t *errtlv;
279     errtlv = aim_gettlv(tlvlist, 0x0008, 1);
280     sess->logininfo.errorcode = aimutil_get16(errtlv->value);
281     sess->logininfo.errorurl = aim_gettlv_str(tlvlist, 0x0004, 1);
282   }
283   /* 
284    * If we have both an IP number (0x0005) and a cookie (0x0006),
285    * then the login was successful.
286    */
287   else if (aim_gettlv(tlvlist, 0x0005, 1) && aim_gettlv(tlvlist, 0x0006, 1) 
288            /*aim_gettlv(tlvlist, 0x0006, 1)->length*/) {
289     struct aim_tlv_t *tmptlv;
290
291     /*
292      * IP address of BOS server.
293      */
294     sess->logininfo.BOSIP = aim_gettlv_str(tlvlist, 0x0005, 1);
295     
296     /*
297      * Authorization Cookie
298      */
299     tmptlv = aim_gettlv(tlvlist, 0x0006, 1);
300     memcpy(sess->logininfo.cookie, tmptlv->value, AIM_COOKIELEN);
301     
302     /*
303      * The email address attached to this account
304      *   Not available for ICQ logins.
305      */
306     if (aim_gettlv(tlvlist, 0x0011, 1))
307       sess->logininfo.email = aim_gettlv_str(tlvlist, 0x0011, 1);
308     
309     /*
310      * The registration status.  (Not real sure what it means.)
311      *   Not available for ICQ logins.
312      */
313     if ((tmptlv = aim_gettlv(tlvlist, 0x0013, 1)))
314       sess->logininfo.regstatus = aimutil_get16(tmptlv->value);
315       
316   }
317
318 #ifdef SNACLOGIN
319   userfunc = aim_callhandler(command->conn, 0x0017, 0x0003);
320 #else
321   userfunc = aim_callhandler(command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_AUTHSUCCESS);
322 #endif
323   if (userfunc)
324     ret = userfunc(sess, command);
325
326   aim_freetlvchain(&tlvlist);
327
328   /* These have been clobbered by the freetlvchain */
329   sess->logininfo.BOSIP = NULL;
330   sess->logininfo.email = NULL;
331   sess->logininfo.errorurl = NULL;
332
333   return ret;
334 }
335
336 /*
337  * Generate an authorization response.  
338  *
339  * You probably don't want this unless you're writing an AIM server.
340  *
341  */
342 unsigned long aim_sendauthresp(struct aim_session_t *sess, 
343                                struct aim_conn_t *conn, 
344                                char *sn, char *bosip, 
345                                char *cookie, char *email, 
346                                int regstatus)
347 {       
348   struct command_tx_struct *tx;
349   struct aim_tlvlist_t *tlvlist = NULL;
350
351   if (!(tx = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0004, conn, 1152)))
352     return -1;
353   
354   tx->lock = 1;
355
356   if (sn)
357     aim_addtlvtochain_str(&tlvlist, 0x0001, sn, strlen(sn));
358   else
359     aim_addtlvtochain_str(&tlvlist, 0x0001, sess->logininfo.screen_name, strlen(sess->logininfo.screen_name));
360
361   if (sess->logininfo.errorcode) {
362     aim_addtlvtochain16(&tlvlist, 0x0008, sess->logininfo.errorcode);
363     aim_addtlvtochain_str(&tlvlist, 0x0004, sess->logininfo.errorurl, strlen(sess->logininfo.errorurl));
364   } else {
365     aim_addtlvtochain_str(&tlvlist, 0x0005, bosip, strlen(bosip));
366     aim_addtlvtochain_str(&tlvlist, 0x0006, cookie, AIM_COOKIELEN);
367     aim_addtlvtochain_str(&tlvlist, 0x0011, email, strlen(email));
368     aim_addtlvtochain16(&tlvlist, 0x0013, regstatus);
369   }
370
371   tx->commandlen = aim_writetlvchain(tx->data, tx->commandlen, &tlvlist);
372   tx->lock = 0;
373   return aim_tx_enqueue(sess, tx);
374 }
375
376 /*
377  * Generate a random cookie.  (Non-client use only)
378  */
379 int aim_gencookie(unsigned char *buf)
380 {
381   int i;
382
383   srand(time(NULL));
384
385   for (i=0; i < AIM_COOKIELEN; i++)
386     buf[i] = 1+(int) (256.0*rand()/(RAND_MAX+0.0));
387
388   return i;
389 }
390
391 /*
392  * Send Server Ready.  (Non-client)
393  */
394 int aim_sendserverready(struct aim_session_t *sess, struct aim_conn_t *conn)
395 {
396   struct command_tx_struct *tx;
397   int i = 0;
398
399   if (!(tx = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+0x22)))
400     return -1;
401
402   tx->lock = 1;
403
404   i += aim_putsnac(tx->data, 0x0001, 0x0003, 0x0000, sess->snac_nextid++);
405   
406   i += aimutil_put16(tx->data+i, 0x0001);  
407   i += aimutil_put16(tx->data+i, 0x0002);
408   i += aimutil_put16(tx->data+i, 0x0003);
409   i += aimutil_put16(tx->data+i, 0x0004);
410   i += aimutil_put16(tx->data+i, 0x0006);
411   i += aimutil_put16(tx->data+i, 0x0008);
412   i += aimutil_put16(tx->data+i, 0x0009);
413   i += aimutil_put16(tx->data+i, 0x000a);
414   i += aimutil_put16(tx->data+i, 0x000b);
415   i += aimutil_put16(tx->data+i, 0x000c);
416   i += aimutil_put16(tx->data+i, 0x0013);
417   i += aimutil_put16(tx->data+i, 0x0015);
418
419   tx->commandlen = i;
420   tx->lock = 0;
421   return aim_tx_enqueue(sess, tx);
422 }
423
424
425 /* 
426  * Send service redirect.  (Non-Client)
427  */
428 unsigned long aim_sendredirect(struct aim_session_t *sess, 
429                                struct aim_conn_t *conn, 
430                                unsigned short servid, 
431                                char *ip,
432                                char *cookie)
433 {       
434   struct command_tx_struct *tx;
435   struct aim_tlvlist_t *tlvlist = NULL;
436   int i = 0;
437
438   if (!(tx = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 1152)))
439     return -1;
440
441   tx->lock = 1;
442
443   i += aimutil_put16(tx->data+i, 0x0001);
444   i += aimutil_put16(tx->data+i, 0x0005);
445   i += aimutil_put16(tx->data+i, 0x0000);
446   i += aimutil_put16(tx->data+i, 0x0000);
447   i += aimutil_put16(tx->data+i, 0x0000);
448   
449   aim_addtlvtochain16(&tlvlist, 0x000d, servid);
450   aim_addtlvtochain_str(&tlvlist, 0x0005, ip, strlen(ip));
451   aim_addtlvtochain_str(&tlvlist, 0x0006, cookie, AIM_COOKIELEN);
452
453   tx->commandlen = aim_writetlvchain(tx->data+i, tx->commandlen-i, &tlvlist)+i;
454   aim_freetlvchain(&tlvlist);
455
456   tx->lock = 0;
457   return aim_tx_enqueue(sess, tx);
458 }
This page took 2.278335 seconds and 5 git commands to generate.