# HG changeset patch # User Mark Doliner # Date 1146702813 0 # Node ID 1983a8fc8e7248a102e5beb854ec40cdc91a8f72 # Parent 4997b8b66206404003f3cff035ead6db0a319add [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 diff -r 4997b8b66206 -r 1983a8fc8e72 src/ntlm.c --- 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; idxflags = 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; }