From 9e6b0c28712ee77ce878809c8576826a3ba08d95 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Wed, 19 Mar 2008 10:17:42 +1100 Subject: Merge lorikeet-heimdal -r 787 into Samba4 tree. Andrew Bartlett (This used to be commit d88b530522d3cef67c24422bd5182fb875d87ee2) --- source4/heimdal/lib/ntlm/heimntlm-protos.h | 11 +- source4/heimdal/lib/ntlm/heimntlm.h | 81 ++++++--- source4/heimdal/lib/ntlm/ntlm.c | 278 ++++++++++++++++++++++++----- 3 files changed, 297 insertions(+), 73 deletions(-) (limited to 'source4/heimdal/lib/ntlm') diff --git a/source4/heimdal/lib/ntlm/heimntlm-protos.h b/source4/heimdal/lib/ntlm/heimntlm-protos.h index 438ba2b94d..bc64791b43 100644 --- a/source4/heimdal/lib/ntlm/heimntlm-protos.h +++ b/source4/heimdal/lib/ntlm/heimntlm-protos.h @@ -43,7 +43,7 @@ heim_ntlm_calculate_ntlm2_sess ( int heim_ntlm_decode_targetinfo ( - struct ntlm_buf */*data*/, + const struct ntlm_buf */*data*/, int /*ucs2*/, struct ntlm_targetinfo */*ti*/); @@ -65,7 +65,7 @@ heim_ntlm_decode_type3 ( int heim_ntlm_encode_targetinfo ( - struct ntlm_targetinfo */*ti*/, + const struct ntlm_targetinfo */*ti*/, int /*ucs2*/, struct ntlm_buf */*data*/); @@ -76,14 +76,17 @@ heim_ntlm_encode_type1 ( int heim_ntlm_encode_type2 ( - struct ntlm_type2 */*type2*/, + const struct ntlm_type2 */*type2*/, struct ntlm_buf */*data*/); int heim_ntlm_encode_type3 ( - struct ntlm_type3 */*type3*/, + const struct ntlm_type3 */*type3*/, struct ntlm_buf */*data*/); +void +heim_ntlm_free_buf (struct ntlm_buf */*p*/); + void heim_ntlm_free_targetinfo (struct ntlm_targetinfo */*ti*/); diff --git a/source4/heimdal/lib/ntlm/heimntlm.h b/source4/heimdal/lib/ntlm/heimntlm.h index 1c1afe1eb1..09d2205fd2 100644 --- a/source4/heimdal/lib/ntlm/heimntlm.h +++ b/source4/heimdal/lib/ntlm/heimntlm.h @@ -31,17 +31,22 @@ * SUCH DAMAGE. */ -/* $Id: heimntlm.h 19469 2006-12-20 07:28:37Z lha $ */ +/* $Id: heimntlm.h 22376 2007-12-28 18:38:23Z lha $ */ #ifndef HEIM_NTLM_H #define HEIM_NTLM_H +/** + * Buffer for storing data in the NTLM library. When filled in by the + * library it should be freed with heim_ntlm_free_buf(). + */ struct ntlm_buf { - size_t length; - void *data; + size_t length; /**< length buffer data */ + void *data; /**< pointer to the data itself */ }; #define NTLM_NEG_UNICODE 0x00000001 +#define NTLM_NEG_TARGET 0x00000004 #define NTLM_NEG_SIGN 0x00000010 #define NTLM_NEG_SEAL 0x00000020 #define NTLM_NEG_NTLM 0x00000200 @@ -52,42 +57,66 @@ struct ntlm_buf { #define NTLM_NEG_ALWAYS_SIGN 0x00008000 #define NTLM_NEG_NTLM2_SESSION 0x00080000 -#define NTLM_NEG_TARGET_DOMAIN 0x00010000 +#define NTLM_TARGET_DOMAIN 0x00010000 +#define NTLM_TARGET_SERVER 0x00020000 #define NTLM_ENC_128 0x20000000 #define NTLM_NEG_KEYEX 0x40000000 +/** + * Struct for the NTLM target info, the strings is assumed to be in + * UTF8. When filled in by the library it should be freed with + * heim_ntlm_free_targetinfo(). + */ struct ntlm_targetinfo { - char *servername; - char *domainname; - char *dnsdomainname; - char *dnsservername; + char *servername; /**< */ + char *domainname; /**< */ + char *dnsdomainname; /**< */ + char *dnsservername; /**< */ }; +/** + * Struct for the NTLM type1 message info, the strings is assumed to + * be in UTF8. When filled in by the library it should be freed with + * heim_ntlm_free_type1(). + */ + struct ntlm_type1 { - uint32_t flags; - char *domain; - char *hostname; - uint32_t os[2]; + uint32_t flags; /**< */ + char *domain; /**< */ + char *hostname; /**< */ + uint32_t os[2]; /**< */ }; +/** + * Struct for the NTLM type2 message info, the strings is assumed to + * be in UTF8. When filled in by the library it should be freed with + * heim_ntlm_free_type2(). + */ + struct ntlm_type2 { - uint32_t flags; - char *targetname; - struct ntlm_buf targetinfo; - unsigned char challange[8]; - uint32_t context[2]; - uint32_t os[2]; + uint32_t flags; /**< */ + char *targetname; /**< */ + struct ntlm_buf targetinfo; /**< */ + unsigned char challange[8]; /**< */ + uint32_t context[2]; /**< */ + uint32_t os[2]; /**< */ }; +/** + * Struct for the NTLM type3 message info, the strings is assumed to + * be in UTF8. When filled in by the library it should be freed with + * heim_ntlm_free_type3(). + */ + struct ntlm_type3 { - uint32_t flags; - char *username; - char *targetname; - struct ntlm_buf lm; - struct ntlm_buf ntlm; - struct ntlm_buf sessionkey; - char *ws; - uint32_t os[2]; + uint32_t flags; /**< */ + char *username; /**< */ + char *targetname; /**< */ + struct ntlm_buf lm; /**< */ + struct ntlm_buf ntlm; /**< */ + struct ntlm_buf sessionkey; /**< */ + char *ws; /**< */ + uint32_t os[2]; /**< */ }; #include diff --git a/source4/heimdal/lib/ntlm/ntlm.c b/source4/heimdal/lib/ntlm/ntlm.c index 671bf329e8..f3dccfaca1 100644 --- a/source4/heimdal/lib/ntlm/ntlm.c +++ b/source4/heimdal/lib/ntlm/ntlm.c @@ -33,7 +33,7 @@ #include -RCSID("$Id: ntlm.c 21604 2007-07-17 06:48:55Z lha $"); +RCSID("$Id: ntlm.c 22370 2007-12-28 16:12:01Z lha $"); #include #include @@ -51,12 +51,37 @@ RCSID("$Id: ntlm.c 21604 2007-07-17 06:48:55Z lha $"); #include - -/* - * Source of NTLM information: - * http://davenport.sourceforge.net/ntlm.html +/*! \mainpage Heimdal NTLM library + * + * \section intro Introduction + * + * Heimdal libheimntlm library is a implementation of the NTLM + * protocol, both version 1 and 2. The GSS-API mech that uses this + * library adds support for transport encryption and integrity + * checking. + * + * NTLM is a protocol for mutual authentication, its still used in + * many protocol where Kerberos is not support, one example is + * EAP/X802.1x mechanism LEAP from Microsoft and Cisco. + * + * This is a support library for the core protocol, its used in + * Heimdal to implement and GSS-API mechanism. There is also support + * in the KDC to do remote digest authenticiation, this to allow + * services to authenticate users w/o direct access to the users ntlm + * hashes (same as Kerberos arcfour enctype hashes). + * + * More information about the NTLM protocol can found here + * http://davenport.sourceforge.net/ntlm.html . + * + * The Heimdal projects web page: http://www.h5l.org/ */ +/** @defgroup ntlm_core Heimdal NTLM library + * + * The NTLM core functions implement the string2key generation + * function, message encode and decode function, and the hash function + * functions. + */ struct sec_buffer { uint16_t length; @@ -73,8 +98,16 @@ static const unsigned char ntlmsigature[8] = "NTLMSSP\x00"; #define CHECK(f, e) \ do { ret = f ; if (ret != (e)) { ret = EINVAL; goto out; } } while(0) -static void -_ntlm_free_buf(struct ntlm_buf *p) +/** + * heim_ntlm_free_buf frees the ntlm buffer + * + * @param p buffer to be freed + * + * @ingroup ntlm_core + */ + +void +heim_ntlm_free_buf(struct ntlm_buf *p) { if (p->data) free(p->data); @@ -96,7 +129,7 @@ ascii2ucs2le(const char *string, int up, struct ntlm_buf *buf) buf->length = len * 2; buf->data = malloc(buf->length); if (buf->data == NULL && len != 0) { - _ntlm_free_buf(buf); + heim_ntlm_free_buf(buf); return ENOMEM; } @@ -104,7 +137,7 @@ ascii2ucs2le(const char *string, int up, struct ntlm_buf *buf) for (i = 0; i < len; i++) { unsigned char t = (unsigned char)string[i]; if (t & 0x80) { - _ntlm_free_buf(buf); + heim_ntlm_free_buf(buf); return EINVAL; } if (up) @@ -201,7 +234,7 @@ put_string(krb5_storage *sp, int ucs2, const char *s) CHECK(krb5_storage_write(sp, buf.data, buf.length), buf.length); if (ucs2) - _ntlm_free_buf(&buf); + heim_ntlm_free_buf(&buf); ret = 0; out: return ret; @@ -226,7 +259,7 @@ out: } static krb5_error_code -put_buf(krb5_storage *sp, struct ntlm_buf *buf) +put_buf(krb5_storage *sp, const struct ntlm_buf *buf) { krb5_error_code ret; CHECK(krb5_storage_write(sp, buf->data, buf->length), buf->length); @@ -235,8 +268,12 @@ out: return ret; } -/* +/** + * Frees the ntlm_targetinfo message + * + * @param ti targetinfo to be freed * + * @ingroup ntlm_core */ void @@ -260,8 +297,22 @@ out: return ret; } +/** + * Encodes a ntlm_targetinfo message. + * + * @param ti the ntlm_targetinfo message to encode. + * @param ucs2 if the strings should be encoded with ucs2 (selected by flag in message). + * @param data is the return buffer with the encoded message, should be + * freed with heim_ntlm_free_buf(). + * + * @return In case of success 0 is return, an errors, a errno in what + * went wrong. + * + * @ingroup ntlm_core + */ + int -heim_ntlm_encode_targetinfo(struct ntlm_targetinfo *ti, +heim_ntlm_encode_targetinfo(const struct ntlm_targetinfo *ti, int ucs2, struct ntlm_buf *data) { @@ -299,16 +350,34 @@ out: return ret; } +/** + * Decodes an NTLM targetinfo message + * + * @param data input data buffer with the encode NTLM targetinfo message + * @param ucs2 if the strings should be encoded with ucs2 (selected by flag in message). + * @param ti the decoded target info, should be freed with heim_ntlm_free_targetinfo(). + * + * @return In case of success 0 is return, an errors, a errno in what + * went wrong. + * + * @ingroup ntlm_core + */ + int -heim_ntlm_decode_targetinfo(struct ntlm_buf *data, int ucs2, +heim_ntlm_decode_targetinfo(const struct ntlm_buf *data, + int ucs2, struct ntlm_targetinfo *ti) { memset(ti, 0, sizeof(*ti)); return 0; } -/* - * encoder/decoder type1 messages +/** + * Frees the ntlm_type1 message + * + * @param data message to be freed + * + * @ingroup ntlm_core */ void @@ -367,6 +436,19 @@ out: return ret; } +/** + * Encodes an ntlm_type1 message. + * + * @param type1 the ntlm_type1 message to encode. + * @param data is the return buffer with the encoded message, should be + * freed with heim_ntlm_free_buf(). + * + * @return In case of success 0 is return, an errors, a errno in what + * went wrong. + * + * @ingroup ntlm_core + */ + int heim_ntlm_encode_type1(const struct ntlm_type1 *type1, struct ntlm_buf *data) { @@ -435,8 +517,12 @@ out: return ret; } -/* - * encoder/decoder type 2 messages +/** + * Frees the ntlm_type2 message + * + * @param data message to be freed + * + * @ingroup ntlm_core */ void @@ -444,7 +530,7 @@ heim_ntlm_free_type2(struct ntlm_type2 *data) { if (data->targetname) free(data->targetname); - _ntlm_free_buf(&data->targetinfo); + heim_ntlm_free_buf(&data->targetinfo); memset(data, 0, sizeof(*data)); } @@ -499,8 +585,21 @@ out: return ret; } +/** + * Encodes an ntlm_type2 message. + * + * @param type2 the ntlm_type2 message to encode. + * @param data is the return buffer with the encoded message, should be + * freed with heim_ntlm_free_buf(). + * + * @return In case of success 0 is return, an errors, a errno in what + * went wrong. + * + * @ingroup ntlm_core + */ + int -heim_ntlm_encode_type2(struct ntlm_type2 *type2, struct ntlm_buf *data) +heim_ntlm_encode_type2(const struct ntlm_type2 *type2, struct ntlm_buf *data) { struct sec_buffer targetname, targetinfo; krb5_error_code ret; @@ -562,22 +661,26 @@ out: return ret; } -/* - * encoder/decoder type 2 messages +/** + * Frees the ntlm_type3 message + * + * @param data message to be freed + * + * @ingroup ntlm_core */ void heim_ntlm_free_type3(struct ntlm_type3 *data) { - _ntlm_free_buf(&data->lm); - _ntlm_free_buf(&data->ntlm); + heim_ntlm_free_buf(&data->lm); + heim_ntlm_free_buf(&data->ntlm); if (data->targetname) free(data->targetname); if (data->username) free(data->username); if (data->ws) free(data->ws); - _ntlm_free_buf(&data->sessionkey); + heim_ntlm_free_buf(&data->sessionkey); memset(data, 0, sizeof(*data)); } @@ -629,7 +732,7 @@ heim_ntlm_decode_type3(const struct ntlm_buf *buf, CHECK(ret_buf(in, &ntlm, &type3->ntlm), 0); CHECK(ret_string(in, ucs2, &target, &type3->targetname), 0); CHECK(ret_string(in, ucs2, &username, &type3->username), 0); - CHECK(ret_string(in, ucs2, &username, &type3->ws), 0); + CHECK(ret_string(in, ucs2, &ws, &type3->ws), 0); if (sessionkey.offset) CHECK(ret_buf(in, &sessionkey, &type3->sessionkey), 0); @@ -641,8 +744,21 @@ out: return ret; } +/** + * Encodes an ntlm_type3 message. + * + * @param type3 the ntlm_type3 message to encode. + * @param data is the return buffer with the encoded message, should be + * freed with heim_ntlm_free_buf(). + * + * @return In case of success 0 is return, an errors, a errno in what + * went wrong. + * + * @ingroup ntlm_core + */ + int -heim_ntlm_encode_type3(struct ntlm_type3 *type3, struct ntlm_buf *data) +heim_ntlm_encode_type3(const struct ntlm_type3 *type3, struct ntlm_buf *data) { struct sec_buffer lm, ntlm, target, username, sessionkey, ws; krb5_error_code ret; @@ -766,8 +882,16 @@ splitandenc(unsigned char *hash, memset(key, 0, sizeof(key)); } -/* - * String-to-key function for NTLM +/** + * Calculate the NTLM key, the password is assumed to be in UTF8. + * + * @param password password to calcute the key for. + * @param key calcuted key, should be freed with heim_ntlm_free_buf(). + * + * @return In case of success 0 is return, an errors, a errno in what + * went wrong. + * + * @ingroup ntlm_core */ int @@ -784,18 +908,28 @@ heim_ntlm_nt_key(const char *password, struct ntlm_buf *key) ret = ascii2ucs2le(password, 0, &buf); if (ret) { - _ntlm_free_buf(key); + heim_ntlm_free_buf(key); return ret; } MD4_Init(&ctx); MD4_Update(&ctx, buf.data, buf.length); MD4_Final(key->data, &ctx); - _ntlm_free_buf(&buf); + heim_ntlm_free_buf(&buf); return 0; } -/* +/** * Calculate NTLMv1 response hash + * + * @param key the ntlm v1 key + * @param len length of key + * @param challange sent by the server + * @param answer calculated answer, should be freed with heim_ntlm_free_buf(). + * + * @return In case of success 0 is return, an errors, a errno in what + * went wrong. + * + * @ingroup ntlm_core */ int @@ -823,8 +957,18 @@ heim_ntlm_calculate_ntlm1(void *key, size_t len, return 0; } -/* - * Calculate NTLMv1 master key +/** + * Generates an NTLMv1 session random with assosited session master key. + * + * @param key the ntlm v1 key + * @param len length of key + * @param session generated session nonce, should be freed with heim_ntlm_free_buf(). + * @param master calculated session master key, should be freed with heim_ntlm_free_buf(). + * + * @return In case of success 0 is return, an errors, a errno in what + * went wrong. + * + * @ingroup ntlm_core */ int @@ -849,8 +993,8 @@ heim_ntlm_build_ntlm1_master(void *key, size_t len, master->length = MD4_DIGEST_LENGTH; master->data = malloc(master->length); if (master->data == NULL) { - _ntlm_free_buf(master); - _ntlm_free_buf(session); + heim_ntlm_free_buf(master); + heim_ntlm_free_buf(session); return EINVAL; } @@ -866,8 +1010,8 @@ heim_ntlm_build_ntlm1_master(void *key, size_t len, } if (RAND_bytes(session->data, session->length) != 1) { - _ntlm_free_buf(master); - _ntlm_free_buf(session); + heim_ntlm_free_buf(master); + heim_ntlm_free_buf(session); return EINVAL; } @@ -877,8 +1021,16 @@ heim_ntlm_build_ntlm1_master(void *key, size_t len, return 0; } -/* +/** + * Generates an NTLMv2 session key. + * + * @param key the ntlm key + * @param len length of key + * @param username name of the user, as sent in the message, assumed to be in UTF8. + * @param target the name of the target, assumed to be in UTF8. + * @param ntlmv2 the ntlmv2 session key * + * @ingroup ntlm_core */ void @@ -932,8 +1084,22 @@ nt2unixtime(uint64_t t) } -/* +/** * Calculate NTLMv2 response + * + * @param key the ntlm key + * @param len length of key + * @param username name of the user, as sent in the message, assumed to be in UTF8. + * @param target the name of the target, assumed to be in UTF8. + * @param serverchallange challange as sent by the server in the type2 message. + * @param infotarget infotarget as sent by the server in the type2 message. + * @param ntlmv2 calculated session key + * @param answer ntlm response answer, should be freed with heim_ntlm_free_buf(). + * + * @return In case of success 0 is return, an errors, a errno in what + * went wrong. + * + * @ingroup ntlm_core */ int @@ -1020,8 +1186,23 @@ out: static const int authtimediff = 3600 * 2; /* 2 hours */ -/* +/** * Verify NTLMv2 response. + * + * @param key the ntlm key + * @param len length of key + * @param username name of the user, as sent in the message, assumed to be in UTF8. + * @param target the name of the target, assumed to be in UTF8. + * @param now the time now (0 if the library should pick it up itself) + * @param serverchallange challange as sent by the server in the type2 message. + * @param answer ntlm response answer, should be freed with heim_ntlm_free_buf(). + * @param infotarget infotarget as sent by the server in the type2 message. + * @param ntlmv2 calculated session key + * + * @return In case of success 0 is return, an errors, a errno in what + * went wrong. + * + * @ingroup ntlm_core */ int @@ -1110,13 +1291,13 @@ heim_ntlm_verify_ntlm2(const void *key, size_t len, HMAC_CTX_cleanup(&c); if (memcmp(serveranswer, clientanswer, 16) != 0) { - _ntlm_free_buf(infotarget); + heim_ntlm_free_buf(infotarget); return EINVAL; } return 0; out: - _ntlm_free_buf(infotarget); + heim_ntlm_free_buf(infotarget); if (sp) krb5_storage_free(sp); return ret; @@ -1125,6 +1306,17 @@ out: /* * Calculate the NTLM2 Session Response + * + * @param clnt_nonce client nonce + * @param svr_chal server challage + * @param ntlm2_hash ntlm hash + * @param lm The LM response, should be freed with heim_ntlm_free_buf(). + * @param ntlm The NTLM response, should be freed with heim_ntlm_free_buf(). + * + * @return In case of success 0 is return, an errors, a errno in what + * went wrong. + * + * @ingroup ntlm_core */ int -- cgit