Mercurial > pidgin
changeset 13723:1983a8fc8e72
[gaim-migrate @ 16132]
Make the ntlm code a little cleaner (to me, anyway). Add some helpful
comments (to me, anyway). And hopefully fix a bug or two (hostname,
domain, and username are all sent as UCS-2LE now).
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Thu, 04 May 2006 00:33:33 +0000 |
parents | 4997b8b66206 |
children | 65a39e436567 |
files | src/ntlm.c |
diffstat | 1 files changed, 122 insertions(+), 101 deletions(-) [+] |
line wrap: on
line diff
--- a/src/ntlm.c Thu May 04 00:12:33 2006 +0000 +++ b/src/ntlm.c Thu May 04 00:33:33 2006 +0000 @@ -34,20 +34,16 @@ struct type1_message { guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' */ - guint8 type; /* 0x01 */ - guint8 zero1[3]; - short flags; /* 0xb203 */ - guint8 zero2[2]; + guint32 type; /* 0x00000001 */ + guint32 flags; /* 0x0000b203 */ short dom_len1; /* domain string length */ short dom_len2; /* domain string length */ - short dom_off; /* domain string offset */ - guint8 zero3[2]; + guint32 dom_off; /* domain string offset */ short host_len1; /* host string length */ short host_len2; /* host string length */ - short host_off; /* host string offset (always 0x20) */ - guint8 zero4[2]; + guint32 host_off; /* host string offset (always 0x00000020) */ #if 0 guint8 host[*]; /* host string (ASCII) */ @@ -57,54 +53,49 @@ struct type2_message { guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/ - guint8 type; /* 0x02 */ - guint8 zero1[7]; - short msg_len; /* 0x28 */ - guint8 zero2[2]; - guint32 flags; /* 0x8201 */ + guint32 type; /* 0x00000002 */ + + short msg_len1; /* target name length */ + short msg_len2; /* target name length */ + guint32 msg_off; /* target name offset (always 0x00000048) */ + + guint32 flags; /* 0x00008201 */ guint8 nonce[8]; /* nonce */ - guint8 zero[8]; + guint8 context[8]; }; struct type3_message { guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/ - guint8 type; /* 0x03 */ - guint8 zero1[3]; + guint32 type; /* 0x00000003 */ short lm_resp_len1; /* LanManager response length (always 0x18)*/ short lm_resp_len2; /* LanManager response length (always 0x18)*/ - short lm_resp_off; /* LanManager response offset */ - guint8 zero2[2]; + guint32 lm_resp_off; /* LanManager response offset */ short nt_resp_len1; /* NT response length (always 0x18) */ short nt_resp_len2; /* NT response length (always 0x18) */ - short nt_resp_off; /* NT response offset */ - guint8 zero3[2]; + guint32 nt_resp_off; /* NT response offset */ short dom_len1; /* domain string length */ short dom_len2; /* domain string length */ - short dom_off; /* domain string offset (always 0x40) */ - guint8 zero4[2]; + guint32 dom_off; /* domain string offset (always 0x00000040) */ short user_len1; /* username string length */ short user_len2; /* username string length */ - short user_off; /* username string offset */ - guint8 zero5[2]; + guint32 user_off; /* username string offset */ short host_len1; /* host string length */ short host_len2; /* host string length */ - short host_off; /* host string offset */ - guint8 zero6[2]; + guint32 host_off; /* host string offset */ short sess_len1; short sess_len2; - short sess_off; /* message length */ - guint8 zero7[2]; + guint32 sess_off; /* message length */ - guint32 flags; /* 0x8201 */ -/* guint32 flags2; unknown, used in windows messenger - guint32 flags3; */ + guint32 flags; /* 0x00008201 */ + /* guint32 flags2; */ /* unknown, used in windows messenger */ + /* guint32 flags3; */ #if 0 guint8 dom[*]; /* domain string (unicode UTF-16LE) */ @@ -119,9 +110,16 @@ gchar * gaim_ntlm_gen_type1(const gchar *hostname, const gchar *domain) { + int hostnamelen; + int domainlen; + unsigned char *msg; + struct type1_message *tmsg; gchar *tmp; - char *msg = g_malloc0(sizeof(struct type1_message) + strlen(hostname) + strlen(domain)); - struct type1_message *tmsg = (struct type1_message*)msg; + + hostnamelen = strlen(hostname); + domainlen = strlen(domain); + msg = g_malloc0(sizeof(struct type1_message) + hostnamelen + domainlen); + tmsg = (struct type1_message*)msg; tmsg->protocol[0] = 'N'; tmsg->protocol[1] = 'T'; tmsg->protocol[2] = 'L'; @@ -130,17 +128,18 @@ tmsg->protocol[5] = 'S'; tmsg->protocol[6] = 'P'; tmsg->protocol[7] = '\0'; - tmsg->type= 0x01; - tmsg->flags = 0xb202; - tmsg->dom_len1 = tmsg->dom_len2 = strlen(domain); - tmsg->dom_off = 32+strlen(hostname); - tmsg->host_len1 = tmsg->host_len2 = strlen(hostname); - tmsg->host_off= 32; - memcpy(msg+sizeof(struct type1_message),hostname,strlen(hostname)); - memcpy(msg+sizeof(struct type1_message)+strlen(hostname),domain,strlen(domain)); + tmsg->type = 0x00000001; + tmsg->flags = 0x0000b202; + tmsg->dom_len1 = tmsg->dom_len2 = domainlen; + tmsg->dom_off = sizeof(struct type1_message) + hostnamelen; + tmsg->host_len1 = tmsg->host_len2 = hostnamelen; + tmsg->host_off = sizeof(struct type1_message); + memcpy(msg + tmsg->host_off, hostname, hostnamelen); + memcpy(msg + tmsg->dom_off, domain, domainlen); - tmp = gaim_base64_encode((guchar*)msg, sizeof(struct type1_message) + strlen(hostname) + strlen(domain)); + tmp = gaim_base64_encode(msg, sizeof(struct type1_message) + hostnamelen + domainlen); g_free(msg); + return tmp; } @@ -148,11 +147,15 @@ gaim_ntlm_parse_type2(const gchar *type2, guint32 *flags) { gsize retlen; + struct type2_message *tmsg; static guint8 nonce[8]; - struct type2_message *tmsg = (struct type2_message*)gaim_base64_decode((char*)type2, &retlen); + + tmsg = (struct type2_message*)gaim_base64_decode(type2, &retlen); memcpy(nonce, tmsg->nonce, 8); - if(flags) *flags = tmsg->flags; + if (flags != NULL) + *flags = tmsg->flags; g_free(tmsg); + return nonce; } @@ -177,7 +180,7 @@ * helper function for gaim cipher.c */ static void -des_ecb_encrypt(const guint8 *plaintext, char *result, const guint8 *key) +des_ecb_encrypt(const guint8 *plaintext, guint8 *result, const guint8 *key) { GaimCipher *cipher; GaimCipherContext *context; @@ -186,7 +189,7 @@ cipher = gaim_ciphers_find_cipher("des"); context = gaim_cipher_context_new(cipher, NULL); gaim_cipher_context_set_key(context, key); - gaim_cipher_context_encrypt(context, (guchar*)plaintext, 8, (guchar*)result, &outlen); + gaim_cipher_context_encrypt(context, plaintext, 8, result, &outlen); gaim_cipher_context_destroy(context); } @@ -200,13 +203,13 @@ { guint8 key[8]; setup_des_key(keys, key); - des_ecb_encrypt(plaintext, (char*)results, key); + des_ecb_encrypt(plaintext, results, key); - setup_des_key(keys+7, key); - des_ecb_encrypt(plaintext, (char*)(results+8), key); + setup_des_key(keys + 7, key); + des_ecb_encrypt(plaintext, results + 8, key); - setup_des_key(keys+14, key); - des_ecb_encrypt(plaintext, (char*)(results+16), key); + setup_des_key(keys + 14, key); + des_ecb_encrypt(plaintext, results + 16, key); } static void @@ -225,24 +228,33 @@ gchar * gaim_ntlm_gen_type3(const gchar *username, const gchar *passw, const gchar *hostname, const gchar *domain, const guint8 *nonce, guint32 *flags) { - char lm_pw[14]; + char lm_pw[14]; unsigned char lm_hpw[21]; char sesskey[16]; guint8 key[8]; - int msglen = sizeof(struct type3_message)+ - strlen(domain) + strlen(username)+ - strlen(hostname) + 24 +24 + ((flags) ? 16 : 0); - struct type3_message *tmsg = g_malloc0(msglen); - int len = strlen(passw); + int domainlen; + int usernamelen; + int hostnamelen; + int msglen; + struct type3_message *tmsg; + int passwlen, lennt; unsigned char lm_resp[24], nt_resp[24]; unsigned char magic[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 }; unsigned char nt_hpw[21]; - int lennt; - char nt_pw[128]; + char nt_pw[128]; GaimCipher *cipher; GaimCipherContext *context; - char *tmp = 0; - int idx = 0; + char *tmp; + int idx; + gchar *ucs2le; + + domainlen = strlen(domain) * 2; + usernamelen = strlen(username) * 2; + hostnamelen = strlen(hostname) * 2; + msglen = sizeof(struct type3_message) + domainlen + + usernamelen + hostnamelen + 0x18 + 0x18 + ((flags) ? 0x10 : 0); + tmsg = g_malloc0(msglen); + passwlen = strlen(passw); /* type3 message initialization */ tmsg->protocol[0] = 'N'; @@ -252,79 +264,87 @@ tmsg->protocol[4] = 'S'; tmsg->protocol[5] = 'S'; tmsg->protocol[6] = 'P'; - tmsg->type = 0x03; + tmsg->type = 0x00000003; tmsg->lm_resp_len1 = tmsg->lm_resp_len2 = 0x18; - tmsg->lm_resp_off = sizeof(struct type3_message) + strlen(domain) + strlen(username) + strlen(hostname); + tmsg->lm_resp_off = sizeof(struct type3_message) + domainlen + usernamelen + hostnamelen; tmsg->nt_resp_len1 = tmsg->nt_resp_len2 = 0x18; - tmsg->nt_resp_off = sizeof(struct type3_message) + strlen(domain) + strlen(username) + strlen(hostname) + 0x18; + tmsg->nt_resp_off = sizeof(struct type3_message) + domainlen + usernamelen + hostnamelen + 0x18; - tmsg->dom_len1 = tmsg->dom_len2 = strlen(domain); - tmsg->dom_off = 0x40; + tmsg->dom_len1 = tmsg->dom_len2 = domainlen; + tmsg->dom_off = sizeof(struct type3_message); - tmsg->user_len1 = tmsg->user_len2 = strlen(username); - tmsg->user_off = sizeof(struct type3_message) + strlen(domain); + tmsg->user_len1 = tmsg->user_len2 = usernamelen; + tmsg->user_off = sizeof(struct type3_message) + domainlen; - tmsg->host_len1 = tmsg->host_len2 = strlen(hostname); - tmsg->host_off = sizeof(struct type3_message) + strlen(domain) + strlen(username); + tmsg->host_len1 = tmsg->host_len2 = hostnamelen; + tmsg->host_off = sizeof(struct type3_message) + domainlen + usernamelen; if(flags) { - tmsg->sess_off = sizeof(struct type3_message) + strlen(domain) + strlen(username) + strlen(hostname) + 0x18 + 0x18; - tmsg->sess_len1 = tmsg->sess_len2 = 0x10; + tmsg->sess_off = sizeof(struct type3_message) + domainlen + usernamelen + hostnamelen + 0x18 + 0x18; + tmsg->sess_len1 = tmsg->sess_len2 = 0x0010; } - tmsg->flags = 0x8200; + tmsg->flags = 0x00008200; + + tmp = (char *)tmsg + sizeof(struct type3_message); + + ucs2le = g_convert(domain, -1, "UCS-2LE", "UTF-8", NULL, NULL, NULL); + memcpy(tmp, ucs2le, domainlen); + g_free(ucs2le); + tmp += domainlen; - tmp = ((char*) tmsg) + sizeof(struct type3_message); - strcpy(tmp, domain); - tmp += strlen(domain); - strcpy(tmp, username); - tmp += strlen(username); - strcpy(tmp, hostname); - tmp += strlen(hostname); + ucs2le = g_convert(username, -1, "UCS-2LE", "UTF-8", NULL, NULL, NULL); + memcpy(tmp, ucs2le, usernamelen); + g_free(ucs2le); + tmp += usernamelen; + + ucs2le = g_convert(hostname, -1, "UCS-2LE", "UTF-8", NULL, NULL, NULL); + memcpy(tmp, ucs2le, hostnamelen); + g_free(ucs2le); + tmp += hostnamelen; /* LM */ - if (len > 14) len = 14; + if (passwlen > 14) + passwlen = 14; - for (idx=0; idx<len; idx++) + for (idx = 0; idx < passwlen; idx++) lm_pw[idx] = g_ascii_toupper(passw[idx]); - for (; idx<14; idx++) + for (; idx < 14; idx++) lm_pw[idx] = 0; setup_des_key((unsigned char*)lm_pw, key); - des_ecb_encrypt(magic, (char*)lm_hpw, key); + des_ecb_encrypt(magic, lm_hpw, key); + + setup_des_key((unsigned char*)(lm_pw + 7), key); + des_ecb_encrypt(magic, lm_hpw + 8, key); - setup_des_key((unsigned char*)(lm_pw+7), key); - des_ecb_encrypt(magic, (char*)lm_hpw+8, key); - - memset(lm_hpw+16, 0, 5); + memset(lm_hpw + 16, 0, 5); calc_resp(lm_hpw, nonce, lm_resp); + memcpy(tmp, lm_resp, 0x18); + tmp += 0x18; /* NTLM */ + /* Convert the password to UCS-2LE */ lennt = strlen(passw); - for (idx=0; idx<lennt; idx++) + for (idx = 0; idx < lennt; idx++) { - nt_pw[2*idx] = passw[idx]; - nt_pw[2*idx+1] = 0; + nt_pw[2 * idx] = passw[idx]; + nt_pw[2 * idx + 1] = 0; } cipher = gaim_ciphers_find_cipher("md4"); context = gaim_cipher_context_new(cipher, NULL); - gaim_cipher_context_append(context, (guchar*)nt_pw, 2*lennt); - gaim_cipher_context_digest(context, 21, (guchar*)nt_hpw, NULL); + gaim_cipher_context_append(context, (guint8 *)nt_pw, 2 * lennt); + gaim_cipher_context_digest(context, 21, nt_hpw, NULL); gaim_cipher_context_destroy(context); - memset(nt_hpw+16, 0, 5); - - + memset(nt_hpw + 16, 0, 5); calc_resp(nt_hpw, nonce, nt_resp); - memcpy(tmp, lm_resp, 0x18); - tmp += 0x18; memcpy(tmp, nt_resp, 0x18); tmp += 0x18; - /* LCS Stuff */ - if(flags) { + if (flags) { tmsg->flags = 0x409082d4; gensesskey(sesskey, NULL); memcpy(tmp, sesskey, 0x10); @@ -333,7 +353,8 @@ /*tmsg->flags2 = 0x0a280105; tmsg->flags3 = 0x0f000000;*/ - tmp = gaim_base64_encode((guchar*) tmsg, msglen); + tmp = gaim_base64_encode((guchar *)tmsg, msglen); g_free(tmsg); + return tmp; }