summaryrefslogtreecommitdiffstats
path: root/ntlm/ntlmstruct.c
diff options
context:
space:
mode:
Diffstat (limited to 'ntlm/ntlmstruct.c')
-rw-r--r--ntlm/ntlmstruct.c331
1 files changed, 331 insertions, 0 deletions
diff --git a/ntlm/ntlmstruct.c b/ntlm/ntlmstruct.c
new file mode 100644
index 0000000..dfb80de
--- /dev/null
+++ b/ntlm/ntlmstruct.c
@@ -0,0 +1,331 @@
+/*
+ * Authentication module for the Micr$oft NTLM mechanism.
+ *
+ * This file is part of libESMTP, a library for submission of RFC 2822
+ * formatted electronic mail messages using the SMTP protocol described
+ * in RFC 2821.
+ *
+ * Copyright (C) 2002 Brian Stafford <brian@stafford.uklinux.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "ntlm.h"
+
+/* Must have at least 32 bits in an int (at least pending a more thorough
+ code review - this module is still experimental) */
+#if SIZEOF_UNSIGNED_INT < 32 / 8
+# error "unsigned int is less than 32 bits wide"
+#endif
+
+#if SIZEOF_UNSIGNED_SHORT == 16 / 8
+typedef unsigned short unsigned16_t;
+#else
+#include <sys/types.h>
+typedef uint16 unsigned16_t;
+#endif
+
+#if SIZEOF_UNSIGNED_INT == 32 / 8
+typedef unsigned int unsigned32_t;
+#elif SIZEOF_UNSIGNED_LONG == 32 / 8
+typedef unsigned long unsigned32_t;
+#else
+#include <sys/types.h>
+typedef uint32 unsigned32_t;
+#endif
+
+#ifdef WORDS_BIGENDIAN
+/* Everything in NTLM is little endian binary, therefore byte swapping
+ is needed on big endian platforms. For simplicity, always provide
+ byte swapping functions rather than trying to detect the local
+ platform's support. These functions make no effort to be efficient
+ since this code doesn't require efficient byte swapping. */
+
+#define SWAP(a,b) do { unsigned char s = u.swap[(a)]; \
+ u.swap[(a)] = u.swap[(b)]; \
+ u.swap[(b)] = s; } while (0)
+
+static unsigned16_t
+bswap_16 (unsigned16_t value)
+{
+ union { unsigned16_t val; unsigned char swap[2]; } u;
+
+ u.val = value;
+ SWAP(0,1);
+ return u.val;
+}
+
+static unsigned32_t
+bswap_32 (unsigned32_t value)
+{
+ union u32 { unsigned32_t val; unsigned char swap[4]; } u;
+
+ u.val = value;
+ SWAP(0,3);
+ SWAP(1,2);
+ return u.val;
+}
+
+#undef SWAP
+#endif
+
+static void
+write_uint16 (char *buf, size_t offset, unsigned int value)
+{
+ unsigned16_t i16 = value;
+
+ assert (sizeof i16 == 2);
+#ifdef WORDS_BIGENDIAN
+ i16 = bswap_16 (i16);
+#endif
+ memcpy (buf + offset, &i16, sizeof i16);
+}
+
+static inline void
+write_uint32 (char *buf, size_t offset, unsigned int value)
+{
+ unsigned32_t i32 = value;
+
+ assert (sizeof i32 == 4);
+#ifdef WORDS_BIGENDIAN
+ i32 = bswap_32 (i32);
+#endif
+ memcpy (buf + offset, &i32, sizeof i32);
+}
+
+static inline unsigned int
+read_uint16 (const char *buf, size_t offset)
+{
+ unsigned16_t i16;
+
+ assert (sizeof i16 == 2);
+ memcpy (&i16, buf + offset, sizeof i16);
+#ifdef WORDS_BIGENDIAN
+ i16 = bswap_16 (i16);
+#endif
+ return i16;
+}
+
+static inline unsigned int
+read_uint32 (const char *buf, size_t offset)
+{
+ unsigned32_t i32;
+
+ assert (sizeof i32 == 4);
+ memcpy (&i32, buf + offset, sizeof i32);
+#ifdef WORDS_BIGENDIAN
+ i32 = bswap_32 (i32);
+#endif
+ return i32;
+}
+
+static inline void
+write_string (char *buf, size_t offset, size_t *str_offset,
+ const void *data, size_t len)
+{
+ if (data == NULL)
+ len = 0;
+ write_uint16 (buf, offset, len);
+ write_uint16 (buf, offset + 2, len);
+ write_uint32 (buf, offset + 4, *str_offset);
+ if (len > 0)
+ memcpy (buf + *str_offset, data, len);
+ *str_offset += len;
+}
+
+/* Offsets into on-the-wire NTLM structures */
+#define PROTOCOL 0 /* "NTLMSSP" */
+#define MSGTYPE 8 /* 1..3 */
+/* Type 1 fields */
+#define T1FLAGS 12 /* 0xb203 */
+#define T1DOMAIN 16 /* domain to authenticate in */
+#define T1WKSTN 24 /* client workstation name */
+#define T1SIZE 32
+/* Type 2 fields */
+#define T2AUTHTARGET 12 /* domain/server */
+#define T2FLAGS 20 /* 0x8201 */
+#define T2NONCE 24 /* server challenge */
+#define T2RESERVED 32
+#define T2SIZE 40
+/* Type 3 fields */
+#define T3LMRESPONSE 12 /* lanmanager hash */
+#define T3NTRESPONSE 20 /* nt hash */
+#define T3DOMAIN 28 /* domain to authenticate against */
+#define T3USER 36 /* user name */
+#define T3WKSTN 44 /* client workstation name */
+#define T3SESSIONKEY 52 /* client workstation name */
+#define T3FLAGS 60 /* 0xb203 */
+#define T3SIZE 64
+
+static const char NTLMSSP[] = "NTLMSSP";
+
+/* Build a NTLM type 1 structure in the buffer.
+ domain - the NT domain the workstation belongs to
+ workstation - the NT (netbios) name of the workstation */
+size_t
+ntlm_build_type_1 (char *buf, size_t buflen, unsigned int flags,
+ const char *domain, const char *workstation)
+{
+ size_t offset = T1SIZE;
+ size_t len;
+ unsigned char *up;
+ char string[256];
+
+ if (buflen < offset)
+ return 0;
+ memcpy (buf, NTLMSSP, 8);
+ write_uint32 (buf, MSGTYPE, 1);
+ write_uint32 (buf, T1FLAGS, flags);
+ up = NULL;
+ len = 0;
+ if (domain != NULL)
+ {
+ len = strlen (domain);
+ if (offset + len > buflen)
+ return 0;
+ lm_uccpy (string, len, domain);
+ }
+ write_string (buf, T1DOMAIN, &offset, string, len);
+ up = NULL;
+ len = 0;
+ if (workstation != NULL)
+ {
+ len = strlen (workstation);
+ if (offset + len > buflen)
+ return 0;
+ lm_uccpy (string, len, workstation);
+ }
+ write_string (buf, T1WKSTN, &offset, string, len);
+ return offset;
+}
+
+/* Build a NTLM type 2 structure in the buffer */
+size_t
+ntlm_build_type_2 (char *buf, size_t buflen, unsigned int flags,
+ const unsigned char *nonce, const char *domain)
+{
+ size_t offset = T2SIZE;
+ size_t len;
+ char string[256];
+ unsigned char *up;
+
+ if (buflen < offset)
+ return 0;
+ memcpy (buf, NTLMSSP, 8);
+ write_uint32 (buf, MSGTYPE, 2);
+ up = NULL;
+ len = 0;
+ if (domain != NULL)
+ {
+ len = strlen (domain);
+ if (offset + 2 * len > buflen)
+ return 0;
+ up = nt_unicode (lm_uccpy (string, len, domain), 2 * len);
+ }
+ write_string (buf, T2AUTHTARGET, &offset, up, len);
+ if (up != NULL)
+ free (up);
+ write_uint32 (buf, T2FLAGS, flags);
+ memcpy (buf + T2NONCE, nonce, 8);
+ memset (buf + T2RESERVED, 0, 8);
+ return offset;
+}
+
+/* Build a NTLM type 3 structure in the buffer */
+size_t
+ntlm_build_type_3 (char *buf, size_t buflen, unsigned int flags,
+ const unsigned char *lm_resp, const unsigned char *nt_resp,
+ const char *domain, const char *user, const char *workstation)
+{
+ size_t offset = T3SIZE;
+ size_t len;
+ char string[256];
+ unsigned char *up;
+
+ if (buflen + 24 + 24 < offset)
+ return 0;
+ memcpy (buf, NTLMSSP, 8);
+ write_uint32 (buf, MSGTYPE, 3);
+ write_string (buf, T3LMRESPONSE, &offset, lm_resp, 24);
+ write_string (buf, T3NTRESPONSE, &offset, nt_resp, 24);
+ up = NULL;
+ len = 0;
+ if (domain != NULL)
+ {
+ len = strlen (domain);
+ if (offset + 2 * len > buflen)
+ return 0;
+ up = nt_unicode (lm_uccpy (string, len, domain), 2 * len);
+ }
+ write_string (buf, T3DOMAIN, &offset, up, 2 * len);
+ if (up != NULL)
+ free (up);
+ up = NULL;
+ len = 0;
+ if (user != NULL)
+ {
+ len = strlen (user);
+ if (offset + 2 * len > buflen)
+ return 0;
+ up = nt_unicode (lm_uccpy (string, len, user), 2 * len);
+ }
+ write_string (buf, T3USER, &offset, up, 2 * len);
+ if (up != NULL)
+ free (up);
+ up = NULL;
+ len = 0;
+ if (workstation != NULL)
+ {
+ len = strlen (workstation);
+ if (offset + 2 * len > buflen)
+ return 0;
+ up = nt_unicode (lm_uccpy (string, len, workstation), 2 * len);
+ }
+ write_string (buf, T3WKSTN, &offset, up, 2 * len);
+ if (up != NULL)
+ free (up);
+ write_string (buf, T3SESSIONKEY, &offset, NULL, 0);
+ write_uint32 (buf, T3FLAGS, flags);
+ return offset;
+}
+
+/****/
+
+/* Parse a NTLM type 2 structure in the buffer (partial implementation).
+ Verify that the packet is a type 2 structure and copy the nonce to the
+ supplied buffer (which must be eight bytes long) */
+size_t
+ntlm_parse_type_2 (const char *buf, size_t buflen, unsigned int *flags,
+ unsigned char *nonce, char **domain)
+{
+ if (buflen < T2SIZE)
+ return 0;
+ if (memcmp (buf, NTLMSSP, 8) != 0)
+ return 0;
+ if (read_uint32 (buf, MSGTYPE) != 2)
+ return 0;
+ *flags = read_uint32 (buf, T2FLAGS);
+ *domain = NULL;
+ memcpy (nonce, buf + T2NONCE, 8);
+ return 1;
+}
+