]> andersk Git - libfaim.git/blob - aim_login.c
- Fri Jun 30 00:04:47 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(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     }
102     if (strlen(password) > 8) {
103       printf("faim: icq: password too long (8 char max)\n");
104     }
105   }
106
107 #ifdef SNACLOGIN 
108   newpacket->commandlen = 10;
109   newpacket->commandlen += 2 + 2 + strlen(sn);
110   newpacket->commandlen += 2 + 2 + strlen(password);
111   newpacket->commandlen += 2 + 2 + strlen(clientinfo->clientstring);
112   newpacket->commandlen += 56;
113   
114   newpacket->lock = 1;
115
116   curbyte = aim_putsnac(newpacket->data+curbyte, 0x0017, 0x0002, 0x0000, 0x00010000);
117   curbyte+= aim_puttlv_str(newpacket->data+curbyte, 0x0001, strlen(sn), sn);
118   password_encoded = (u_char *) malloc(strlen(password));
119   aim_encode_password(password, password_encoded);
120   curbyte+= aim_puttlv_str(newpacket->data+curbyte, 0x0002, strlen(password), password_encoded);
121   curbyte+= aim_puttlv_str(newpacket->data+curbyte, 0x0003, 
122                            strlen(clientinfo->clientstring), 
123                            clientinfo->clientstring);
124   /* XXX: should use clientinfo provided version info */
125   curbyte+= aim_puttlv_16(newpacket->data+curbyte, 0x0016, 0x0004);
126   curbyte+= aim_puttlv_16(newpacket->data+curbyte, 0x0017, 0x0003);
127   curbyte+= aim_puttlv_16(newpacket->data+curbyte, 0x0018, 0x0005);
128   curbyte+= aim_puttlv_16(newpacket->data+curbyte, 0x0019, 0x0000);
129   curbyte+= aim_puttlv_16(newpacket->data+curbyte, 0x001a, 0x0686);
130   curbyte+= aim_puttlv_str(newpacket->data+curbyte, 0x0001, 0x0002, clientinfo->country);
131   curbyte+= aim_puttlv_str(newpacket->data+curbyte, 0x0001, 0x0002, clientinfo->lang);
132   curbyte+= aim_puttlv_32(newpacket->data+curbyte, 0x0014, 0x0000002a);
133   curbyte+= aim_puttlv_16(newpacket->data+curbyte, 0x0009, 0x0015);
134 #else
135   
136   newpacket->lock = 1;
137   newpacket->hdr.oscar.type = 0x01;
138
139   /*
140    * These four bytes are actually the FLAP version information.
141    * They're sent here for convenience.  I suppose they could
142    * be seperated out into a seperate FLAP, but this is where
143    * everyone else sends them.
144    */
145   curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000);
146   curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001);
147
148   curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x0001, strlen(sn), sn);
149
150   password_encoded = (char *) malloc(strlen(password));
151   aim_encode_password(password, password_encoded);
152   curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x0002, strlen(password), password_encoded);
153   free(password_encoded);
154   
155   /* XXX is clientstring required by oscar? */
156   if (strlen(clientinfo->clientstring))
157     curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x0003, strlen(clientinfo->clientstring), clientinfo->clientstring);
158
159   curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0016, clientinfo->major2);
160   curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0017, clientinfo->major);
161   curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0018, clientinfo->minor);
162   curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0019, clientinfo->minor2);
163   curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x001a, clientinfo->build);
164
165   curbyte += aim_puttlv_32(newpacket->data+curbyte, 0x0014, clientinfo->unknown);
166
167   if (strlen(clientinfo->country))
168     curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x000e, strlen(clientinfo->country), clientinfo->country);
169   else
170     curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x000e, 2, "us");
171
172   if (strlen(clientinfo->lang))
173     curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x000f, strlen(clientinfo->lang), clientinfo->lang);
174   else
175     curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x000f, 2, "en");
176   
177   newpacket->commandlen = curbyte;
178 #endif
179
180   newpacket->lock = 0;
181   return aim_tx_enqueue(sess, newpacket);
182 }
183
184 /*
185  *  int encode_password(
186  *                      const char *password,
187  *                      char *encoded
188  *                      ); 
189  *
190  * This takes a const pointer to a (null terminated) string
191  * containing the unencoded password.  It also gets passed
192  * an already allocated buffer to store the encoded password.
193  * This buffer should be the exact length of the password without
194  * the null.  The encoded password buffer IS NOT NULL TERMINATED.
195  *
196  * The encoding_table seems to be a fixed set of values.  We'll
197  * hope it doesn't change over time!  
198  *
199  */
200 int aim_encode_password(const char *password, u_char *encoded)
201 {
202   u_char encoding_table[] = {
203 #if 0 /* old v1 table */
204     0xf3, 0xb3, 0x6c, 0x99,
205     0x95, 0x3f, 0xac, 0xb6,
206     0xc5, 0xfa, 0x6b, 0x63,
207     0x69, 0x6c, 0xc3, 0x9f
208 #else /* v2.1 table, also works for ICQ */
209     0xf3, 0x26, 0x81, 0xc4,
210     0x39, 0x86, 0xdb, 0x92,
211     0x71, 0xa3, 0xb9, 0xe6,
212     0x53, 0x7a, 0x95, 0x7c
213 #endif
214   };
215
216   int i;
217   
218   for (i = 0; i < strlen(password); i++)
219       encoded[i] = (password[i] ^ encoding_table[i]);
220
221   return 0;
222 }
223
224 /*
225  * This is sent back as a general response to the login command.
226  * It can be either an error or a success, depending on the
227  * precense of certain TLVs.  
228  *
229  * The client should check the value of logininfo->errorcode. If
230  * its nonzero, there was an error.
231  *
232  */
233 int aim_authparse(struct aim_session_t *sess, 
234                   struct command_rx_struct *command)
235 {
236   struct aim_tlvlist_t *tlvlist;
237   int ret = 1;
238   char *sn;
239   rxcallback_t userfunc = NULL;
240
241   memset(&sess->logininfo, 0x00, sizeof(sess->logininfo));
242
243   /*
244    * Read block of TLVs.  All further data is derived
245    * from what is parsed here.
246    */
247 #ifdef SNACLOGIN
248   tlvlist = aim_readtlvchain(command->data+10, command->commandlen-10);
249 #else
250   tlvlist = aim_readtlvchain(command->data, command->commandlen);
251 #endif
252   /*
253    * No matter what, we should have a screen name.
254    */
255   sn = aim_gettlv_str(tlvlist, 0x0001, 1);
256   memcpy(sess->logininfo.screen_name, sn, strlen(sn));
257   sn[(strlen(sn))] = '\0';
258   
259   /*
260    * Check for an error code.  If so, we should also
261    * have an error url.
262    */
263   if (aim_gettlv(tlvlist, 0x0008, 1)) {
264     struct aim_tlv_t *errtlv;
265     errtlv = aim_gettlv(tlvlist, 0x0008, 1);
266     sess->logininfo.errorcode = aimutil_get16(errtlv->value);
267     sess->logininfo.errorurl = aim_gettlv_str(tlvlist, 0x0004, 1);
268   }
269   /* 
270    * If we have both an IP number (0x0005) and a cookie (0x0006),
271    * then the login was successful.
272    */
273   else if (aim_gettlv(tlvlist, 0x0005, 1) && aim_gettlv(tlvlist, 0x0006, 1) 
274            /*aim_gettlv(tlvlist, 0x0006, 1)->length*/) {
275     struct aim_tlv_t *tmptlv;
276
277     /*
278      * IP address of BOS server.
279      */
280     sess->logininfo.BOSIP = aim_gettlv_str(tlvlist, 0x0005, 1);
281     
282     /*
283      * Authorization Cookie
284      */
285     tmptlv = aim_gettlv(tlvlist, 0x0006, 1);
286     memcpy(sess->logininfo.cookie, tmptlv->value, AIM_COOKIELEN);
287     
288     /*
289      * The email address attached to this account
290      *   Not available for ICQ logins.
291      */
292     if (aim_gettlv(tlvlist, 0x0011, 1))
293       sess->logininfo.email = aim_gettlv_str(tlvlist, 0x0011, 1);
294     
295     /*
296      * The registration status.  (Not real sure what it means.)
297      *   Not available for ICQ logins.
298      */
299     if ((tmptlv = aim_gettlv(tlvlist, 0x0013, 1)))
300       sess->logininfo.regstatus = aimutil_get16(tmptlv->value);
301       
302   }
303
304 #ifdef SNACLOGIN
305   userfunc = aim_callhandler(command->conn, 0x0017, 0x0003);
306 #else
307   userfunc = aim_callhandler(command->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_AUTHSUCCESS);
308 #endif
309   if (userfunc)
310     ret = userfunc(sess, command);
311
312   aim_freetlvchain(&tlvlist);
313
314   /* These have been clobbered by the freetlvchain */
315   sess->logininfo.BOSIP = NULL;
316   sess->logininfo.email = NULL;
317   sess->logininfo.errorurl = NULL;
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 0.292977 seconds and 5 git commands to generate.