]> andersk Git - libfaim.git/blame - aim_login.c
- Wed Nov 8 02:23:25 UTC 2000
[libfaim.git] / aim_login.c
CommitLineData
9de3ca7e 1/*
2 * aim_login.c
3 *
4 * This contains all the functions needed to actually login.
5 *
6 */
7
a25832e6 8#include <faim/aim.h>
9de3ca7e 9
b5bc2a8c 10#include "md5.h"
11
12static int aim_encode_password_md5(const char *password, const char *key, md5_byte_t *digest);
9de3ca7e 13
14/*
15 * FIXME: Reimplement the TIS stuff.
16 */
17#ifdef TIS_TELNET_PROXY
18#include "tis_telnet_proxy.h"
19#endif
20
78b3fb13 21faim_export int aim_sendconnack(struct aim_session_t *sess,
22 struct aim_conn_t *conn)
01b59e1e 23{
24 int curbyte=0;
25
5b79dc93 26 struct command_tx_struct *newpacket;
01b59e1e 27
b69540e3 28 if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0001, conn, 4)))
01b59e1e 29 return -1;
30
5b79dc93 31 newpacket->lock = 1;
01b59e1e 32
5b79dc93 33 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0000);
34 curbyte += aimutil_put16(newpacket->data+curbyte, 0x0001);
01b59e1e 35
5b79dc93 36 newpacket->lock = 0;
37 return aim_tx_enqueue(sess, newpacket);
01b59e1e 38}
39
01b59e1e 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 */
78b3fb13 48faim_export int aim_request_login(struct aim_session_t *sess,
49 struct aim_conn_t *conn,
50 char *sn)
01b59e1e 51{
52 int curbyte=0;
53
5b79dc93 54 struct command_tx_struct *newpacket;
01b59e1e 55
b69540e3 56 if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+2+2+strlen(sn))))
5b79dc93 57 return -1;
01b59e1e 58
5b79dc93 59 newpacket->lock = 1;
01b59e1e 60
5b79dc93 61 curbyte += aim_putsnac(newpacket->data+curbyte, 0x0017, 0x0006, 0x0000, 0x00010000);
62 curbyte += aim_puttlv_str(newpacket->data+curbyte, 0x0001, strlen(sn), sn);
01b59e1e 63
5b79dc93 64 newpacket->lock = 0;
65 return aim_tx_enqueue(sess, newpacket);
01b59e1e 66}
01b59e1e 67
9de3ca7e 68/*
24286d93 69 * send_login(int socket, char *sn, char *password)
9de3ca7e 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 *
9de3ca7e 77 */
78b3fb13 78faim_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)
9de3ca7e 83{
9de3ca7e 84 int curbyte=0;
b5bc2a8c 85 md5_byte_t digest[16];
5e02cf44 86
5b79dc93 87 struct command_tx_struct *newpacket;
9de3ca7e 88
01b59e1e 89 if (!clientinfo || !sn || !password)
90 return -1;
91
b69540e3 92 if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 1152)))
5b79dc93 93 return -1;
9de3ca7e 94
5b79dc93 95 newpacket->lock = 1;
01b59e1e 96
b5bc2a8c 97 newpacket->hdr.oscar.type = 0x02;
98
5b79dc93 99 curbyte = aim_putsnac(newpacket->data+curbyte, 0x0017, 0x0002, 0x0000, 0x00010000);
b5bc2a8c 100
5b79dc93 101 curbyte+= aim_puttlv_str(newpacket->data+curbyte, 0x0001, strlen(sn), sn);
01b59e1e 102
b5bc2a8c 103 aim_encode_password_md5(password, key, digest);
78b3fb13 104 curbyte+= aim_puttlv_str(newpacket->data+curbyte, 0x0025, 16, (char *)digest);
9de3ca7e 105
13ebc4c4 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
5ac21963 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);
b5bc2a8c 115
13ebc4c4 116 curbyte += aim_puttlv_32(newpacket->data+curbyte, 0x0014, clientinfo->unknown);
b5bc2a8c 117 curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0009, 0x0015);
9de3ca7e 118
13ebc4c4 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;
9de3ca7e 130
5b79dc93 131 newpacket->lock = 0;
132 return aim_tx_enqueue(sess, newpacket);
9de3ca7e 133}
9de3ca7e 134
b5bc2a8c 135static 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
9de3ca7e 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 *
b5bc2a8c 163 * NOTE: This is no longer used. Its here for historical reference.
164 *
9de3ca7e 165 */
b5bc2a8c 166#if 0
167static int aim_encode_password(const char *password, unsigned char *encoded)
9de3ca7e 168{
169 u_char encoding_table[] = {
b69540e3 170#if 0 /* old v1 table */
9de3ca7e 171 0xf3, 0xb3, 0x6c, 0x99,
172 0x95, 0x3f, 0xac, 0xb6,
173 0xc5, 0xfa, 0x6b, 0x63,
174 0x69, 0x6c, 0xc3, 0x9f
b69540e3 175#else /* v2.1 table, also works for ICQ */
5e02cf44 176 0xf3, 0x26, 0x81, 0xc4,
b69540e3 177 0x39, 0x86, 0xdb, 0x92,
178 0x71, 0xa3, 0xb9, 0xe6,
179 0x53, 0x7a, 0x95, 0x7c
180#endif
5e02cf44 181 };
182
183 int i;
b69540e3 184
5e02cf44 185 for (i = 0; i < strlen(password); i++)
186 encoded[i] = (password[i] ^ encoding_table[i]);
187
188 return 0;
189}
b5bc2a8c 190#endif
5e02cf44 191
01b59e1e 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 */
78b3fb13 201faim_internal int aim_authparse(struct aim_session_t *sess,
202 struct command_rx_struct *command)
01b59e1e 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.
b5bc2a8c 214 *
215 * For SNAC login, there's a 17/3 SNAC header in front.
216 *
01b59e1e 217 */
01b59e1e 218 tlvlist = aim_readtlvchain(command->data+10, command->commandlen-10);
b5bc2a8c 219
01b59e1e 220 /*
221 * No matter what, we should have a screen name.
222 */
223 sn = aim_gettlv_str(tlvlist, 0x0001, 1);
b13c9e13 224 strncpy(sess->logininfo.screen_name, sn, strlen(sn));
225 free(sn);
226
01b59e1e 227 /*
228 * Check for an error code. If so, we should also
229 * have an error url.
230 */
5e02cf44 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 }
01b59e1e 237 /*
238 * If we have both an IP number (0x0005) and a cookie (0x0006),
239 * then the login was successful.
240 */
b69540e3 241 else if (aim_gettlv(tlvlist, 0x0005, 1) && aim_gettlv(tlvlist, 0x0006, 1)
242 /*aim_gettlv(tlvlist, 0x0006, 1)->length*/) {
5e02cf44 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))
01b59e1e 261 sess->logininfo.email = aim_gettlv_str(tlvlist, 0x0011, 1);
5e02cf44 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)))
01b59e1e 268 sess->logininfo.regstatus = aimutil_get16(tmptlv->value);
269
5e02cf44 270 }
01b59e1e 271
01b59e1e 272 userfunc = aim_callhandler(command->conn, 0x0017, 0x0003);
b5bc2a8c 273
01b59e1e 274 if (userfunc)
275 ret = userfunc(sess, command);
276
277 aim_freetlvchain(&tlvlist);
278
dad2e696 279 if (sess->logininfo.BOSIP) {
91c55d47 280 free(sess->logininfo.BOSIP);
dad2e696 281 sess->logininfo.BOSIP = NULL;
282 }
283 if (sess->logininfo.email) {
91c55d47 284 free(sess->logininfo.email);
dad2e696 285 sess->logininfo.email = NULL;
286 }
287 if (sess->logininfo.errorurl) {
91c55d47 288 free(sess->logininfo.errorurl);
dad2e696 289 sess->logininfo.errorurl = NULL;
290 }
01b59e1e 291
292 return ret;
293}
e6b05d80 294
b5bc2a8c 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 */
78b3fb13 302faim_internal int aim_authkeyparse(struct aim_session_t *sess, struct command_rx_struct *command)
b5bc2a8c 303{
304 unsigned char *key;
305 int keylen;
306 int ret = 1;
307 rxcallback_t userfunc;
308
309 keylen = aimutil_get16(command->data+10);
98c88242 310 if (!(key = malloc(keylen+1)))
311 return ret;
b5bc2a8c 312 memcpy(key, command->data+12, keylen);
313 key[keylen] = '\0';
314
315 if ((userfunc = aim_callhandler(command->conn, 0x0017, 0x0007)))
78b3fb13 316 ret = userfunc(sess, command, (char *)key);
b5bc2a8c 317
318 free(key);
319
320 return ret;
321}
322
e6b05d80 323/*
324 * Generate an authorization response.
325 *
326 * You probably don't want this unless you're writing an AIM server.
327 *
328 */
78b3fb13 329faim_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)
e6b05d80 334{
5b79dc93 335 struct command_tx_struct *tx;
e6b05d80 336 struct aim_tlvlist_t *tlvlist = NULL;
337
b69540e3 338 if (!(tx = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0004, conn, 1152)))
5b79dc93 339 return -1;
e6b05d80 340
5b79dc93 341 tx->lock = 1;
e6b05d80 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));
5ac21963 355 aim_addtlvtochain16(&tlvlist, 0x0013, (unsigned short)regstatus);
e6b05d80 356 }
357
5b79dc93 358 tx->commandlen = aim_writetlvchain(tx->data, tx->commandlen, &tlvlist);
359 tx->lock = 0;
360 return aim_tx_enqueue(sess, tx);
e6b05d80 361}
362
363/*
364 * Generate a random cookie. (Non-client use only)
365 */
78b3fb13 366faim_export int aim_gencookie(unsigned char *buf)
e6b05d80 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 */
78b3fb13 381faim_export int aim_sendserverready(struct aim_session_t *sess, struct aim_conn_t *conn)
e6b05d80 382{
5b79dc93 383 struct command_tx_struct *tx;
e6b05d80 384 int i = 0;
385
b69540e3 386 if (!(tx = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+0x22)))
5b79dc93 387 return -1;
e6b05d80 388
5b79dc93 389 tx->lock = 1;
e6b05d80 390
67c0bb2f 391 i += aim_putsnac(tx->data, 0x0001, 0x0003, 0x0000, sess->snac_nextid++);
5b79dc93 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);
67c0bb2f 403 i += aimutil_put16(tx->data+i, 0x0013);
404 i += aimutil_put16(tx->data+i, 0x0015);
5b79dc93 405
67c0bb2f 406 tx->commandlen = i;
5b79dc93 407 tx->lock = 0;
5b79dc93 408 return aim_tx_enqueue(sess, tx);
e6b05d80 409}
410
411
412/*
413 * Send service redirect. (Non-Client)
414 */
78b3fb13 415faim_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)
e6b05d80 420{
5b79dc93 421 struct command_tx_struct *tx;
e6b05d80 422 struct aim_tlvlist_t *tlvlist = NULL;
423 int i = 0;
424
b69540e3 425 if (!(tx = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 1152)))
5b79dc93 426 return -1;
427
428 tx->lock = 1;
e6b05d80 429
13ebc4c4 430 i += aim_putsnac(tx->data+i, 0x0001, 0x0005, 0x0000, 0x00000000);
e6b05d80 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
5b79dc93 436 tx->commandlen = aim_writetlvchain(tx->data+i, tx->commandlen-i, &tlvlist)+i;
e6b05d80 437 aim_freetlvchain(&tlvlist);
438
5b79dc93 439 tx->lock = 0;
440 return aim_tx_enqueue(sess, tx);
e6b05d80 441}
This page took 0.145244 seconds and 5 git commands to generate.