]> andersk Git - libfaim.git/blame - aim_login.c
- Sun Sep 3 23:58:17 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
01b59e1e 21int aim_sendconnack(struct aim_session_t *sess,
22 struct aim_conn_t *conn)
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 */
48int aim_request_login(struct aim_session_t *sess,
49 struct aim_conn_t *conn,
50 char *sn)
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 */
a25832e6 78int aim_send_login (struct aim_session_t *sess,
79 struct aim_conn_t *conn,
b5bc2a8c 80 char *sn, char *password, struct client_info_s *clientinfo,
81 char *key)
9de3ca7e 82{
9de3ca7e 83 int curbyte=0;
b5bc2a8c 84 md5_byte_t digest[16];
5e02cf44 85
5b79dc93 86 struct command_tx_struct *newpacket;
9de3ca7e 87
01b59e1e 88 if (!clientinfo || !sn || !password)
89 return -1;
90
b69540e3 91 if (!(newpacket = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 1152)))
5b79dc93 92 return -1;
9de3ca7e 93
5b79dc93 94 newpacket->lock = 1;
01b59e1e 95
b5bc2a8c 96 newpacket->hdr.oscar.type = 0x02;
97
5b79dc93 98 curbyte = aim_putsnac(newpacket->data+curbyte, 0x0017, 0x0002, 0x0000, 0x00010000);
b5bc2a8c 99
5b79dc93 100 curbyte+= aim_puttlv_str(newpacket->data+curbyte, 0x0001, strlen(sn), sn);
01b59e1e 101
b5bc2a8c 102 aim_encode_password_md5(password, key, digest);
103 curbyte+= aim_puttlv_str(newpacket->data+curbyte, 0x0025, 16, digest);
9de3ca7e 104
13ebc4c4 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);
b5bc2a8c 114
13ebc4c4 115 curbyte += aim_puttlv_32(newpacket->data+curbyte, 0x0014, clientinfo->unknown);
b5bc2a8c 116 curbyte += aim_puttlv_16(newpacket->data+curbyte, 0x0009, 0x0015);
9de3ca7e 117
13ebc4c4 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;
9de3ca7e 129
5b79dc93 130 newpacket->lock = 0;
131 return aim_tx_enqueue(sess, newpacket);
9de3ca7e 132}
9de3ca7e 133
b5bc2a8c 134static 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
9de3ca7e 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 *
b5bc2a8c 162 * NOTE: This is no longer used. Its here for historical reference.
163 *
9de3ca7e 164 */
b5bc2a8c 165#if 0
166static int aim_encode_password(const char *password, unsigned char *encoded)
9de3ca7e 167{
168 u_char encoding_table[] = {
b69540e3 169#if 0 /* old v1 table */
9de3ca7e 170 0xf3, 0xb3, 0x6c, 0x99,
171 0x95, 0x3f, 0xac, 0xb6,
172 0xc5, 0xfa, 0x6b, 0x63,
173 0x69, 0x6c, 0xc3, 0x9f
b69540e3 174#else /* v2.1 table, also works for ICQ */
5e02cf44 175 0xf3, 0x26, 0x81, 0xc4,
b69540e3 176 0x39, 0x86, 0xdb, 0x92,
177 0x71, 0xa3, 0xb9, 0xe6,
178 0x53, 0x7a, 0x95, 0x7c
179#endif
5e02cf44 180 };
181
182 int i;
b69540e3 183
5e02cf44 184 for (i = 0; i < strlen(password); i++)
185 encoded[i] = (password[i] ^ encoding_table[i]);
186
187 return 0;
188}
b5bc2a8c 189#endif
5e02cf44 190
01b59e1e 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 */
200int 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.
b5bc2a8c 213 *
214 * For SNAC login, there's a 17/3 SNAC header in front.
215 *
01b59e1e 216 */
01b59e1e 217 tlvlist = aim_readtlvchain(command->data+10, command->commandlen-10);
b5bc2a8c 218
01b59e1e 219 /*
220 * No matter what, we should have a screen name.
221 */
222 sn = aim_gettlv_str(tlvlist, 0x0001, 1);
b13c9e13 223 strncpy(sess->logininfo.screen_name, sn, strlen(sn));
224 free(sn);
225
01b59e1e 226 /*
227 * Check for an error code. If so, we should also
228 * have an error url.
229 */
5e02cf44 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 }
01b59e1e 236 /*
237 * If we have both an IP number (0x0005) and a cookie (0x0006),
238 * then the login was successful.
239 */
b69540e3 240 else if (aim_gettlv(tlvlist, 0x0005, 1) && aim_gettlv(tlvlist, 0x0006, 1)
241 /*aim_gettlv(tlvlist, 0x0006, 1)->length*/) {
5e02cf44 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))
01b59e1e 260 sess->logininfo.email = aim_gettlv_str(tlvlist, 0x0011, 1);
5e02cf44 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)))
01b59e1e 267 sess->logininfo.regstatus = aimutil_get16(tmptlv->value);
268
5e02cf44 269 }
01b59e1e 270
01b59e1e 271 userfunc = aim_callhandler(command->conn, 0x0017, 0x0003);
b5bc2a8c 272
01b59e1e 273 if (userfunc)
274 ret = userfunc(sess, command);
275
276 aim_freetlvchain(&tlvlist);
277
dad2e696 278 if (sess->logininfo.BOSIP) {
91c55d47 279 free(sess->logininfo.BOSIP);
dad2e696 280 sess->logininfo.BOSIP = NULL;
281 }
282 if (sess->logininfo.email) {
91c55d47 283 free(sess->logininfo.email);
dad2e696 284 sess->logininfo.email = NULL;
285 }
286 if (sess->logininfo.errorurl) {
91c55d47 287 free(sess->logininfo.errorurl);
dad2e696 288 sess->logininfo.errorurl = NULL;
289 }
01b59e1e 290
291 return ret;
292}
e6b05d80 293
b5bc2a8c 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 */
301int 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);
98c88242 309 if (!(key = malloc(keylen+1)))
310 return ret;
b5bc2a8c 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
e6b05d80 322/*
323 * Generate an authorization response.
324 *
325 * You probably don't want this unless you're writing an AIM server.
326 *
327 */
328unsigned 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{
5b79dc93 334 struct command_tx_struct *tx;
e6b05d80 335 struct aim_tlvlist_t *tlvlist = NULL;
336
b69540e3 337 if (!(tx = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0004, conn, 1152)))
5b79dc93 338 return -1;
e6b05d80 339
5b79dc93 340 tx->lock = 1;
e6b05d80 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
5b79dc93 357 tx->commandlen = aim_writetlvchain(tx->data, tx->commandlen, &tlvlist);
358 tx->lock = 0;
359 return aim_tx_enqueue(sess, tx);
e6b05d80 360}
361
362/*
363 * Generate a random cookie. (Non-client use only)
364 */
365int 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 */
380int aim_sendserverready(struct aim_session_t *sess, struct aim_conn_t *conn)
381{
5b79dc93 382 struct command_tx_struct *tx;
e6b05d80 383 int i = 0;
384
b69540e3 385 if (!(tx = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 10+0x22)))
5b79dc93 386 return -1;
e6b05d80 387
5b79dc93 388 tx->lock = 1;
e6b05d80 389
67c0bb2f 390 i += aim_putsnac(tx->data, 0x0001, 0x0003, 0x0000, sess->snac_nextid++);
5b79dc93 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);
67c0bb2f 402 i += aimutil_put16(tx->data+i, 0x0013);
403 i += aimutil_put16(tx->data+i, 0x0015);
5b79dc93 404
67c0bb2f 405 tx->commandlen = i;
5b79dc93 406 tx->lock = 0;
5b79dc93 407 return aim_tx_enqueue(sess, tx);
e6b05d80 408}
409
410
411/*
412 * Send service redirect. (Non-Client)
413 */
414unsigned 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{
5b79dc93 420 struct command_tx_struct *tx;
e6b05d80 421 struct aim_tlvlist_t *tlvlist = NULL;
422 int i = 0;
423
b69540e3 424 if (!(tx = aim_tx_new(AIM_FRAMETYPE_OSCAR, 0x0002, conn, 1152)))
5b79dc93 425 return -1;
426
427 tx->lock = 1;
e6b05d80 428
13ebc4c4 429 i += aim_putsnac(tx->data+i, 0x0001, 0x0005, 0x0000, 0x00000000);
e6b05d80 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
5b79dc93 435 tx->commandlen = aim_writetlvchain(tx->data+i, tx->commandlen-i, &tlvlist)+i;
e6b05d80 436 aim_freetlvchain(&tlvlist);
437
5b79dc93 438 tx->lock = 0;
439 return aim_tx_enqueue(sess, tx);
e6b05d80 440}
This page took 0.171745 seconds and 5 git commands to generate.