Back to index

lightning-sunbird  0.9+nobinonly
ReadNTLM.cpp
Go to the documentation of this file.
00001 /* vim: set ts=2 sw=2 et cindent: */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla.
00016  *
00017  * The Initial Developer of the Original Code is IBM Corporation.
00018  * Portions created by IBM Corporation are Copyright (C) 2003
00019  * IBM Corporation. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Darin Fisher <darin@meer.net>
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include <stdlib.h>
00039 #include <stdio.h>
00040 #include "plbase64.h"
00041 #include "nsString.h"
00042 #include "nsNativeCharsetUtils.h"
00043 #include "nsReadableUtils.h"
00044 #include "prmem.h"
00045 
00046 /*
00047  * ReadNTLM : reads NTLM messages.
00048  *
00049  * based on http://davenport.sourceforge.net/ntlm.html
00050  */
00051 
00052 #define kNegotiateUnicode               0x00000001
00053 #define kNegotiateOEM                   0x00000002
00054 #define kRequestTarget                  0x00000004
00055 #define kUnknown1                       0x00000008
00056 #define kNegotiateSign                  0x00000010
00057 #define kNegotiateSeal                  0x00000020
00058 #define kNegotiateDatagramStyle         0x00000040
00059 #define kNegotiateLanManagerKey         0x00000080
00060 #define kNegotiateNetware               0x00000100
00061 #define kNegotiateNTLMKey               0x00000200
00062 #define kUnknown2                       0x00000400
00063 #define kUnknown3                       0x00000800
00064 #define kNegotiateDomainSupplied        0x00001000
00065 #define kNegotiateWorkstationSupplied   0x00002000
00066 #define kNegotiateLocalCall             0x00004000
00067 #define kNegotiateAlwaysSign            0x00008000
00068 #define kTargetTypeDomain               0x00010000
00069 #define kTargetTypeServer               0x00020000
00070 #define kTargetTypeShare                0x00040000
00071 #define kNegotiateNTLM2Key              0x00080000
00072 #define kRequestInitResponse            0x00100000
00073 #define kRequestAcceptResponse          0x00200000
00074 #define kRequestNonNTSessionKey         0x00400000
00075 #define kNegotiateTargetInfo            0x00800000
00076 #define kUnknown4                       0x01000000
00077 #define kUnknown5                       0x02000000
00078 #define kUnknown6                       0x04000000
00079 #define kUnknown7                       0x08000000
00080 #define kUnknown8                       0x10000000
00081 #define kNegotiate128                   0x20000000
00082 #define kNegotiateKeyExchange           0x40000000
00083 #define kNegotiate56                    0x80000000
00084 
00085 static const char NTLM_SIGNATURE[] = "NTLMSSP";
00086 static const char NTLM_TYPE1_MARKER[] = { 0x01, 0x00, 0x00, 0x00 };
00087 static const char NTLM_TYPE2_MARKER[] = { 0x02, 0x00, 0x00, 0x00 };
00088 static const char NTLM_TYPE3_MARKER[] = { 0x03, 0x00, 0x00, 0x00 };
00089 
00090 #define NTLM_MARKER_LEN 4
00091 #define NTLM_TYPE1_HEADER_LEN 32
00092 #define NTLM_TYPE2_HEADER_LEN 32
00093 #define NTLM_TYPE3_HEADER_LEN 64
00094 
00095 #define LM_HASH_LEN 16
00096 #define LM_RESP_LEN 24
00097 
00098 #define NTLM_HASH_LEN 16
00099 #define NTLM_RESP_LEN 24
00100 
00101 static void PrintFlags(PRUint32 flags)
00102 {
00103 #define TEST(_flag) \
00104   if (flags & k ## _flag) \
00105     printf("    0x%08x (" # _flag ")\n", k ## _flag)
00106 
00107   TEST(NegotiateUnicode);
00108   TEST(NegotiateOEM);
00109   TEST(RequestTarget);
00110   TEST(Unknown1);
00111   TEST(NegotiateSign);
00112   TEST(NegotiateSeal);
00113   TEST(NegotiateDatagramStyle);
00114   TEST(NegotiateLanManagerKey);
00115   TEST(NegotiateNetware);
00116   TEST(NegotiateNTLMKey);
00117   TEST(Unknown2);
00118   TEST(Unknown3);
00119   TEST(NegotiateDomainSupplied);
00120   TEST(NegotiateWorkstationSupplied);
00121   TEST(NegotiateLocalCall);
00122   TEST(NegotiateAlwaysSign);
00123   TEST(TargetTypeDomain);
00124   TEST(TargetTypeServer);
00125   TEST(TargetTypeShare);
00126   TEST(NegotiateNTLM2Key);
00127   TEST(RequestInitResponse);
00128   TEST(RequestAcceptResponse);
00129   TEST(RequestNonNTSessionKey);
00130   TEST(NegotiateTargetInfo);
00131   TEST(Unknown4);
00132   TEST(Unknown5);
00133   TEST(Unknown6);
00134   TEST(Unknown7);
00135   TEST(Unknown8);
00136   TEST(Negotiate128);
00137   TEST(NegotiateKeyExchange);
00138   TEST(Negotiate56);
00139 
00140 #undef TEST
00141 }
00142 
00143 static void
00144 PrintBuf(const char *tag, const PRUint8 *buf, PRUint32 bufLen)
00145 {
00146   int i;
00147 
00148   printf("%s =\n", tag);
00149   while (bufLen > 0)
00150   {
00151     int count = bufLen;
00152     if (count > 8)
00153       count = 8;
00154 
00155     printf("    ");
00156     for (i=0; i<count; ++i)
00157     {
00158       printf("0x%02x ", int(buf[i]));
00159     }
00160     for (; i<8; ++i)
00161     {
00162       printf("     ");
00163     }
00164 
00165     printf("   ");
00166     for (i=0; i<count; ++i)
00167     {
00168       if (isprint(buf[i]))
00169         printf("%c", buf[i]);
00170       else
00171         printf(".");
00172     }
00173     printf("\n");
00174 
00175     bufLen -= count;
00176     buf += count;
00177   }
00178 }
00179 
00180 static PRUint16
00181 ReadUint16(const PRUint8 *&buf)
00182 {
00183   PRUint16 x;
00184 #ifdef IS_BIG_ENDIAN
00185   x = ((PRUint16) buf[1]) | ((PRUint16) buf[0] << 8);
00186 #else
00187   x = ((PRUint16) buf[0]) | ((PRUint16) buf[1] << 8);
00188 #endif
00189   buf += sizeof(x);
00190   return x;
00191 }
00192 
00193 static PRUint32
00194 ReadUint32(const PRUint8 *&buf)
00195 {
00196   PRUint32 x;
00197 #ifdef IS_BIG_ENDIAN
00198   x = ( (PRUint32) buf[3])        |
00199       (((PRUint32) buf[2]) << 8)  |
00200       (((PRUint32) buf[1]) << 16) |
00201       (((PRUint32) buf[0]) << 24);
00202 #else
00203   x = ( (PRUint32) buf[0])        |
00204       (((PRUint32) buf[1]) << 8)  |
00205       (((PRUint32) buf[2]) << 16) |
00206       (((PRUint32) buf[3]) << 24);
00207 #endif
00208   buf += sizeof(x);
00209   return x;
00210 }
00211 
00212 typedef struct {
00213   PRUint16 length;
00214   PRUint16 capacity;
00215   PRUint32 offset;
00216 } SecBuf;
00217 
00218 static void
00219 ReadSecBuf(SecBuf *s, const PRUint8 *&buf)
00220 {
00221   s->length = ReadUint16(buf);
00222   s->capacity = ReadUint16(buf);
00223   s->offset = ReadUint32(buf);
00224 }
00225 
00226 static void
00227 ReadType1MsgBody(const PRUint8 *inBuf, PRUint32 start)
00228 {
00229   const PRUint8 *cursor = inBuf + start;
00230   PRUint32 flags;
00231 
00232   PrintBuf("flags", cursor, 4);
00233   // read flags
00234   flags = ReadUint32(cursor);
00235   PrintFlags(flags);
00236 
00237   // type 1 message may not include trailing security buffers
00238   if ((flags & kNegotiateDomainSupplied) | 
00239       (flags & kNegotiateWorkstationSupplied))
00240   {
00241     SecBuf secbuf;
00242     ReadSecBuf(&secbuf, cursor);
00243     PrintBuf("supplied domain", inBuf + secbuf.offset, secbuf.length);
00244 
00245     ReadSecBuf(&secbuf, cursor);
00246     PrintBuf("supplied workstation", inBuf + secbuf.offset, secbuf.length);
00247   }
00248 }
00249 
00250 static void
00251 ReadType2MsgBody(const PRUint8 *inBuf, PRUint32 start)
00252 {
00253   PRUint16 targetLen, offset;
00254   PRUint32 flags;
00255   const PRUint8 *target;
00256   const PRUint8 *cursor = inBuf + start;
00257 
00258   // read target name security buffer
00259   targetLen = ReadUint16(cursor);
00260   ReadUint16(cursor); // discard next 16-bit value
00261   offset = ReadUint32(cursor); // get offset from inBuf
00262   target = inBuf + offset;
00263 
00264   PrintBuf("target", target, targetLen);
00265 
00266   PrintBuf("flags", cursor, 4);
00267   // read flags
00268   flags = ReadUint32(cursor);
00269   PrintFlags(flags);
00270 
00271   // read challenge
00272   PrintBuf("challenge", cursor, 8);
00273   cursor += 8;
00274 
00275   PrintBuf("context", cursor, 8);
00276   cursor += 8;
00277 
00278   SecBuf secbuf;
00279   ReadSecBuf(&secbuf, cursor);
00280   PrintBuf("target information", inBuf + secbuf.offset, secbuf.length);
00281 }
00282 
00283 static void
00284 ReadType3MsgBody(const PRUint8 *inBuf, PRUint32 start)
00285 {
00286   const PRUint8 *cursor = inBuf + start;
00287 
00288   SecBuf secbuf;
00289 
00290   ReadSecBuf(&secbuf, cursor); // LM response
00291   PrintBuf("LM response", inBuf + secbuf.offset, secbuf.length);
00292 
00293   ReadSecBuf(&secbuf, cursor); // NTLM response
00294   PrintBuf("NTLM response", inBuf + secbuf.offset, secbuf.length);
00295 
00296   ReadSecBuf(&secbuf, cursor); // domain name
00297   PrintBuf("domain name", inBuf + secbuf.offset, secbuf.length);
00298 
00299   ReadSecBuf(&secbuf, cursor); // user name
00300   PrintBuf("user name", inBuf + secbuf.offset, secbuf.length);
00301 
00302   ReadSecBuf(&secbuf, cursor); // workstation name
00303   PrintBuf("workstation name", inBuf + secbuf.offset, secbuf.length);
00304 
00305   ReadSecBuf(&secbuf, cursor); // session key
00306   PrintBuf("session key", inBuf + secbuf.offset, secbuf.length);
00307 
00308   PRUint32 flags = ReadUint32(cursor);
00309   PrintBuf("flags", (const PRUint8 *) &flags, sizeof(flags));
00310   PrintFlags(flags);
00311 }
00312 
00313 static void
00314 ReadMsg(const char *base64buf, PRUint32 bufLen)
00315 {
00316   PRUint8 *inBuf = (PRUint8 *) PL_Base64Decode(base64buf, bufLen, NULL);
00317   if (!inBuf)
00318   {
00319     printf("PL_Base64Decode failed\n");
00320     return;
00321   }
00322 
00323   const PRUint8 *cursor = inBuf;
00324 
00325   PrintBuf("signature", cursor, 8);
00326 
00327   // verify NTLMSSP signature
00328   if (memcmp(cursor, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE)) != 0)
00329   {
00330     printf("### invalid or corrupt NTLM signature\n");
00331   }
00332   cursor += sizeof(NTLM_SIGNATURE);
00333 
00334   PrintBuf("message type", cursor, 4);
00335 
00336   if (memcmp(cursor, NTLM_TYPE1_MARKER, sizeof(NTLM_MARKER_LEN)) == 0)
00337     ReadType1MsgBody(inBuf, 12);
00338   else if (memcmp(cursor, NTLM_TYPE2_MARKER, sizeof(NTLM_MARKER_LEN)) == 0)
00339     ReadType2MsgBody(inBuf, 12);
00340   else if (memcmp(cursor, NTLM_TYPE3_MARKER, sizeof(NTLM_MARKER_LEN)) == 0)
00341     ReadType3MsgBody(inBuf, 12);
00342   else
00343     printf("### invalid or unknown message type\n"); 
00344 
00345   PR_Free(inBuf);
00346 }
00347 
00348 int main(int argc, char **argv)
00349 {
00350   if (argc == 1)
00351   {
00352     printf("usage: ntlmread <msg>\n");
00353     return -1;
00354   }
00355   ReadMsg(argv[1], (PRUint32) strlen(argv[1]));
00356   return 0;
00357 }