/* smbutil.c --- Main library functions. * Copyright (C) 2002, 2004, 2005 Simon Josefsson * Copyright (C) 1999-2001 Grant Edwards * Copyright (C) 2004 Frediano Ziglio * * This file 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 file 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 file; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301, USA. * */ #ifdef NTLM_UNIQUE_MODULE #define NTLM_STATIC static #endif #include "global.h" #include #ifdef NTLM_UNIQUE_MODULE # include "des.c" # include "md4.c" # include "smbencrypt.c" #else # include "des.h" # include "md4.h" # include "smbencrypt.h" #endif char versionString[] = PACKAGE_STRING; /* Utility routines that handle NTLM auth structures. */ /* * Must be multiple of two * We use a statis buffer of 1024 bytes for message * At maximun we but 48 bytes (ntlm responses) and 3 unicode strings so * NTLM_BUFSIZE * 3 + 48 <= 1024 */ #define NTLM_BUFSIZE 320 /* * all bytes in our structures are aligned so just swap bytes so * we have just to swap order */ #ifdef WORDS_BIGENDIAN # define UI16LE(n) byteswap16(n) # define UI32LE(n) byteswap32(n) #else # define UI16LE(n) (n) # define UI32LE(n) (n) #endif /* I am not crazy about these macros -- they seem to have gotten * a bit complex. A new scheme for handling string/buffer fields * in the structures probably needs to be designed */ #define AddBytes(ptr, header, buf, count) \ { \ ptr->header.len = ptr->header.maxlen = UI16LE(count); \ ptr->header.offset = UI32LE((ptr->buffer - ((uint8*)ptr)) + ptr->bufIndex); \ memcpy(ptr->buffer+ptr->bufIndex, buf, count); \ ptr->bufIndex += count; \ } #define AddString(ptr, header, string) \ { \ const char *p = (string); \ size_t len = p ? strlen(p) : 0; \ AddBytes(ptr, header, p, len); \ } #define AddUnicodeStringLen(ptr, header, string, len) \ { \ unsigned char buf[NTLM_BUFSIZE]; \ unsigned char *b = strToUnicode(string, len, buf); \ AddBytes(ptr, header, b, len*2); \ } #define AddUnicodeString(ptr, header, string) \ { \ size_t len = strlen(string); \ AddUnicodeStringLen(ptr, header, string, len); \ } #define GetUnicodeString(structPtr, header, output) \ getUnicodeString(UI32LE(structPtr->header.offset), UI16LE(structPtr->header.len), ((char*)structPtr), (structPtr->buffer - (uint8*) structPtr), sizeof(structPtr->buffer), output) #define GetString(structPtr, header, output) \ getString(UI32LE(structPtr->header.offset), UI16LE(structPtr->header.len), ((char*)structPtr), (structPtr->buffer - (uint8*) structPtr), sizeof(structPtr->buffer), output) #define DumpBuffer(fp, structPtr, header) \ dumpBuffer(fp, UI32LE(structPtr->header.offset), UI16LE(structPtr->header.len), ((char*)structPtr), (structPtr->buffer - (uint8*) structPtr), sizeof(structPtr->buffer)) static void dumpRaw (FILE * fp, const unsigned char *buf, size_t len) { size_t i; for (i = 0; i < len; ++i) fprintf (fp, "%02x ", buf[i]); fprintf (fp, "\n"); } static inline void dumpBuffer (FILE * fp, uint32 offset, uint32 len, char *structPtr, size_t buf_start, size_t buf_len) { /* prevent buffer reading overflow */ if (offset < buf_start || offset > buf_len + buf_start || offset + len > buf_len + buf_start) len = 0; dumpRaw (fp, structPtr + offset, len); } static char * unicodeToString (const char *p, size_t len, char *buf) { size_t i; if (len >= NTLM_BUFSIZE) len = NTLM_BUFSIZE - 1; for (i = 0; i < len; ++i) { buf[i] = *p & 0x7f; p += 2; } buf[i] = '\0'; return buf; } static inline char * getUnicodeString (uint32 offset, uint32 len, char *structPtr, size_t buf_start, size_t buf_len, char *output) { /* prevent buffer reading overflow */ if (offset < buf_start || offset > buf_len + buf_start || offset + len > buf_len + buf_start) len = 0; return unicodeToString (structPtr + offset, len / 2, output); } static unsigned char * strToUnicode (const char *p, size_t l, unsigned char *buf) { int i = 0; if (l > (NTLM_BUFSIZE / 2)) l = (NTLM_BUFSIZE / 2); while (l--) { buf[i++] = *p++; buf[i++] = 0; } return buf; } static char * toString (const char *p, size_t len, char *buf) { if (len >= NTLM_BUFSIZE) len = NTLM_BUFSIZE - 1; memcpy (buf, p, len); buf[len] = 0; return buf; } static inline char * getString (uint32 offset, uint32 len, char *structPtr, size_t buf_start, size_t buf_len, char *output) { /* prevent buffer reading overflow */ if (offset < buf_start || offset > buf_len + buf_start || offset + len > buf_len + buf_start) len = 0; return toString (structPtr + offset, len, output); } void dumpSmbNtlmAuthRequest (FILE * fp, tSmbNtlmAuthRequest * request) { char buf1[NTLM_BUFSIZE], buf2[NTLM_BUFSIZE]; fprintf (fp, "NTLM Request:\n" " Ident = %.8s\n" " mType = %d\n" " Flags = %08x\n" " User = %s\n" " Domain = %s\n", request->ident, UI32LE (request->msgType), UI32LE (request->flags), GetString (request, user, buf1), GetString (request, domain, buf2)); } void dumpSmbNtlmAuthChallenge (FILE * fp, tSmbNtlmAuthChallenge * challenge) { unsigned char buf[NTLM_BUFSIZE]; fprintf (fp, "NTLM Challenge:\n" " Ident = %.8s\n" " mType = %d\n" " Domain = %s\n" " Flags = %08x\n" " Challenge = ", challenge->ident, UI32LE (challenge->msgType), GetUnicodeString (challenge, uDomain, buf), UI32LE (challenge->flags)); dumpRaw (fp, challenge->challengeData, 8); } void dumpSmbNtlmAuthResponse (FILE * fp, tSmbNtlmAuthResponse * response) { unsigned char buf1[NTLM_BUFSIZE], buf2[NTLM_BUFSIZE], buf3[NTLM_BUFSIZE]; fprintf (fp, "NTLM Response:\n" " Ident = %.8s\n" " mType = %d\n" " LmResp = ", response->ident, UI32LE (response->msgType)); DumpBuffer (fp, response, lmResponse); fprintf (fp, " NTResp = "); DumpBuffer (fp, response, ntResponse); fprintf (fp, " Domain = %s\n" " User = %s\n" " Wks = %s\n" " sKey = ", GetUnicodeString (response, uDomain, buf1), GetUnicodeString (response, uUser, buf2), GetUnicodeString (response, uWks, buf3)); DumpBuffer (fp, response, sessionKey); fprintf (fp, " Flags = %08x\n", UI32LE (response->flags)); } static void buildSmbNtlmAuthRequest_userlen (tSmbNtlmAuthRequest * request, const char *user, size_t user_len, const char *domain) { request->bufIndex = 0; memcpy (request->ident, "NTLMSSP\0\0\0", 8); request->msgType = UI32LE (1); request->flags = UI32LE (0x0000b207); /* have to figure out what these mean */ /* FIXME this should be workstation, not username */ AddBytes (request, user, user, user_len); AddString (request, domain, domain); } void buildSmbNtlmAuthRequest (tSmbNtlmAuthRequest * request, const char *user, const char *domain) { const char *p = strchr (user, '@'); size_t user_len = strlen (user); if (p) { if (!domain) domain = p + 1; user_len = p - user; } buildSmbNtlmAuthRequest_userlen (request, user, user_len, domain); } void buildSmbNtlmAuthRequest_noatsplit (tSmbNtlmAuthRequest * request, const char *user, const char *domain) { buildSmbNtlmAuthRequest_userlen (request, user, strlen (user), domain); } static void buildSmbNtlmAuthResponse_userlen (tSmbNtlmAuthChallenge * challenge, tSmbNtlmAuthResponse * response, const char *user, size_t user_len, const char *domain, const char *password) { uint8 lmRespData[24]; uint8 ntRespData[24]; SMBencrypt (password, challenge->challengeData, lmRespData); SMBNTencrypt (password, challenge->challengeData, ntRespData); response->bufIndex = 0; memcpy (response->ident, "NTLMSSP\0\0\0", 8); response->msgType = UI32LE (3); AddUnicodeString (response, uDomain, domain); AddUnicodeStringLen (response, uUser, user, user_len); /* TODO just a dummy value for workstation */ AddUnicodeStringLen (response, uWks, user, user_len); AddBytes (response, lmResponse, lmRespData, 24); AddBytes (response, ntResponse, ntRespData, 24); AddString (response, sessionKey, NULL); response->flags = challenge->flags; } void buildSmbNtlmAuthResponse (tSmbNtlmAuthChallenge * challenge, tSmbNtlmAuthResponse * response, const char *user, const char *password) { const char *p = strchr (user, '@'); size_t user_len = strlen (user); unsigned char buf[NTLM_BUFSIZE]; const char *domain = GetUnicodeString (challenge, uDomain, buf); if (p) { domain = p + 1; user_len = p - user; } buildSmbNtlmAuthResponse_userlen (challenge, response, user, user_len, domain, password); } void buildSmbNtlmAuthResponse_noatsplit (tSmbNtlmAuthChallenge * challenge, tSmbNtlmAuthResponse * response, const char *user, const char *password) { unsigned char buf[NTLM_BUFSIZE]; const char *domain = GetUnicodeString (challenge, uDomain, buf); buildSmbNtlmAuthResponse_userlen (challenge, response, user, strlen (user), domain, password); }