C:/Web/smbrelay3/src/ntlm.cpp

Go to the documentation of this file.
00001 
00002 /* $Id$
00003    Single file NTLM system to create and parse authentication messages.
00004 
00005    http://www.reversing.org
00006    ilo-- [email protected]  
00007 
00008    I did copy&paste&modify several files to leave independent NTLM code 
00009    that compile in cygwin/linux environment. Most of the code was ripped 
00010    from Samba implementation so I left the Copying statement. Samba core
00011    code was left unmodified from 1.9 version.
00012 
00013    Also libntlm was ripped but rewrote, due to fixed and useless interface.
00014    Library oriented code was removed. (c) goes to: Simon Josefsson.
00015 
00016    Information about interface to this ntlm-system is in ntlm.h file.
00017 
00018    Unix SMB/Netbios implementation.
00019    Version 1.9.
00020    SMB parameters and setup
00021    Copyright (C) Andrew Tridgell 1992-1998
00022    Modified by Jeremy Allison 1995.
00023    
00024    This program is free software; you can redistribute it and/or modify
00025    it under the terms of the GNU General Public License as published by
00026    the Free Software Foundation; either version 2 of the License, or
00027    (at your option) any later version.
00028    
00029    This program is distributed in the hope that it will be useful,
00030    but WITHOUT ANY WARRANTY; without even the implied warranty of
00031    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00032    GNU General Public License for more details.
00033    
00034    You should have received a copy of the GNU General Public License
00035    along with this program; if not, write to the Free Software
00036    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00037 
00038   NOTE: Some modifications have been added to this library to allow better interaction with smbrelay3
00039   http://www.tarasco.org
00040   Andres Tarasco - [email protected]
00041 */
00042 #define _CRT_SECURE_NO_DEPRECATE
00043 
00044 
00045 #include "ntlm.h"
00046 #include "misc.h"
00047 
00048 #define WORD unsigned short
00049 
00050 
00051 /* Byte order macros */
00052 #ifndef _BYTEORDER_H
00053 #define _BYTEORDER_H
00054 
00055 /*
00056    This file implements macros for machine independent short and 
00057    int manipulation
00058  
00059 Here is a description of this file that I emailed to the samba list once:
00060 
00061 > I am confused about the way that byteorder.h works in Samba. I have
00062 > looked at it, and I would have thought that you might make a distinction
00063 > between LE and BE machines, but you only seem to distinguish between 386
00064 > and all other architectures.
00065 > 
00066 > Can you give me a clue?
00067 
00068 sure.
00069 
00070 The distinction between 386 and other architectures is only there as
00071 an optimisation. You can take it out completely and it will make no
00072 difference. The routines (macros) in byteorder.h are totally byteorder
00073 independent. The 386 optimsation just takes advantage of the fact that
00074 the x86 processors don't care about alignment, so we don't have to
00075 align ints on int boundaries etc. If there are other processors out
00076 there that aren't alignment sensitive then you could also define
00077 CAREFUL_ALIGNMENT=0 on those processors as well.
00078 
00079 Ok, now to the macros themselves. I'll take a simple example, say we
00080 want to extract a 2 byte integer from a SMB packet and put it into a
00081 type called uint16 that is in the local machines byte order, and you
00082 want to do it with only the assumption that uint16 is _at_least_ 16
00083 bits long (this last condition is very important for architectures
00084 that don't have any int types that are 2 bytes long)
00085 
00086 You do this:
00087 
00088 #define CVAL(buf,pos) (((unsigned char *)(buf))[pos])
00089 #define PVAL(buf,pos) ((unsigned)CVAL(buf,pos))
00090 #define SVAL(buf,pos) (PVAL(buf,pos)|PVAL(buf,(pos)+1)<<8)
00091 
00092 then to extract a uint16 value at offset 25 in a buffer you do this:
00093 
00094 char *buffer = foo_bar();
00095 uint16 xx = SVAL(buffer,25);
00096 
00097 We are using the byteoder independence of the ANSI C bitshifts to do
00098 the work. A good optimising compiler should turn this into efficient
00099 code, especially if it happens to have the right byteorder :-)
00100 
00101 I know these macros can be made a bit tidier by removing some of the
00102 casts, but you need to look at byteorder.h as a whole to see the
00103 reasoning behind them. byteorder.h defines the following macros:
00104 
00105 SVAL(buf,pos) - extract a 2 byte SMB value
00106 IVAL(buf,pos) - extract a 4 byte SMB value
00107 SVALS(buf,pos) signed version of SVAL()
00108 IVALS(buf,pos) signed version of IVAL()
00109 
00110 SSVAL(buf,pos,val) - put a 2 byte SMB value into a buffer
00111 SIVAL(buf,pos,val) - put a 4 byte SMB value into a buffer
00112 SSVALS(buf,pos,val) - signed version of SSVAL()
00113 SIVALS(buf,pos,val) - signed version of SIVAL()
00114 
00115 RSVAL(buf,pos) - like SVAL() but for NMB byte ordering
00116 RSVALS(buf,pos) - like SVALS() but for NMB byte ordering
00117 RIVAL(buf,pos) - like IVAL() but for NMB byte ordering
00118 RIVALS(buf,pos) - like IVALS() but for NMB byte ordering
00119 RSSVAL(buf,pos,val) - like SSVAL() but for NMB ordering
00120 RSIVAL(buf,pos,val) - like SIVAL() but for NMB ordering
00121 RSIVALS(buf,pos,val) - like SIVALS() but for NMB ordering
00122 
00123 it also defines lots of intermediate macros, just ignore those :-)
00124 
00125 */
00126 
00127 /* some switch macros that do both store and read to and from SMB buffers */
00128 
00129 #define RW_PCVAL(read,inbuf,outbuf,len) \
00130         { if (read) { PCVAL (inbuf,0,outbuf,len); } \
00131         else      { PSCVAL(inbuf,0,outbuf,len); } }
00132 
00133 #define RW_PIVAL(read,big_endian,inbuf,outbuf,len) \
00134         { if (read) { if (big_endian) { RPIVAL(inbuf,0,outbuf,len); } else { PIVAL(inbuf,0,outbuf,len); } } \
00135         else      { if (big_endian) { RPSIVAL(inbuf,0,outbuf,len); } else { PSIVAL(inbuf,0,outbuf,len); } } }
00136 
00137 #define RW_PSVAL(read,big_endian,inbuf,outbuf,len) \
00138         { if (read) { if (big_endian) { RPSVAL(inbuf,0,outbuf,len); } else { PSVAL(inbuf,0,outbuf,len); } } \
00139         else      { if (big_endian) { RPSSVAL(inbuf,0,outbuf,len); } else { PSSVAL(inbuf,0,outbuf,len); } } }
00140 
00141 #define RW_CVAL(read, inbuf, outbuf, offset) \
00142         { if (read) { (outbuf) = CVAL (inbuf,offset); } \
00143         else      { SCVAL(inbuf,offset,outbuf); } }
00144 
00145 #define RW_IVAL(read, big_endian, inbuf, outbuf, offset) \
00146         { if (read) { (outbuf) = ((big_endian) ? RIVAL(inbuf,offset) : IVAL (inbuf,offset)); } \
00147         else      { if (big_endian) { RSIVAL(inbuf,offset,outbuf); } else { SIVAL(inbuf,offset,outbuf); } } }
00148 
00149 #define RW_SVAL(read, big_endian, inbuf, outbuf, offset) \
00150         { if (read) { (outbuf) = ((big_endian) ? RSVAL(inbuf,offset) : SVAL (inbuf,offset)); } \
00151         else      { if (big_endian) { RSSVAL(inbuf,offset,outbuf); } else { SSVAL(inbuf,offset,outbuf); } } }
00152 
00153 #undef CAREFUL_ALIGNMENT
00154 
00155 /* we know that the 386 can handle misalignment and has the "right" 
00156    byteorder */
00157 #ifdef __i386__
00158 #define CAREFUL_ALIGNMENT 0
00159 #endif
00160 
00161 #ifndef CAREFUL_ALIGNMENT
00162 #define CAREFUL_ALIGNMENT 1
00163 #endif
00164 
00165 #define CVAL(buf,pos) (((unsigned char *)(buf))[pos])
00166 #define PVAL(buf,pos) ((unsigned)CVAL(buf,pos))
00167 #define SCVAL(buf,pos,val) (CVAL(buf,pos) = (val))
00168 
00169 
00170 #if CAREFUL_ALIGNMENT
00171 
00172 #define SVAL(buf,pos) (PVAL(buf,pos)|PVAL(buf,(pos)+1)<<8)
00173 #define IVAL(buf,pos) (SVAL(buf,pos)|SVAL(buf,(pos)+2)<<16)
00174 #define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8)
00175 #define SIVALX(buf,pos,val) (SSVALX(buf,pos,val&0xFFFF),SSVALX(buf,pos+2,val>>16))
00176 #define SVALS(buf,pos) ((int16)SVAL(buf,pos))
00177 #define IVALS(buf,pos) ((int32)IVAL(buf,pos))
00178 #define SSVAL(buf,pos,val) SSVALX((buf),(pos),((uint16)(val)))
00179 #define SIVAL(buf,pos,val) SIVALX((buf),(pos),((uint32)(val)))
00180 #define SSVALS(buf,pos,val) SSVALX((buf),(pos),((int16)(val)))
00181 #define SIVALS(buf,pos,val) SIVALX((buf),(pos),((int32)(val)))
00182 
00183 #else /* CAREFUL_ALIGNMENT */
00184 
00185 /* this handles things for architectures like the 386 that can handle
00186    alignment errors */
00187 /*
00188    WARNING: This section is dependent on the length of int16 and int32
00189    being correct 
00190 */
00191 
00192 /* get single value from an SMB buffer */
00193 #define SVAL(buf,pos) (*(uint16 *)((char *)(buf) + (pos)))
00194 #define IVAL(buf,pos) (*(uint32 *)((char *)(buf) + (pos)))
00195 #define SVALS(buf,pos) (*(int16 *)((char *)(buf) + (pos)))
00196 #define IVALS(buf,pos) (*(int32 *)((char *)(buf) + (pos)))
00197 
00198 /* store single value in an SMB buffer */
00199 #define SSVAL(buf,pos,val) SVAL(buf,pos)=((uint16)(val))
00200 #define SIVAL(buf,pos,val) IVAL(buf,pos)=((uint32)(val))
00201 #define SSVALS(buf,pos,val) SVALS(buf,pos)=((int16)(val))
00202 #define SIVALS(buf,pos,val) IVALS(buf,pos)=((int32)(val))
00203 
00204 #endif /* CAREFUL_ALIGNMENT */
00205 
00206 /* macros for reading / writing arrays */
00207 
00208 #define SMBMACRO(macro,buf,pos,val,len,size) \
00209 { int l; for (l = 0; l < (len); l++) (val)[l] = macro((buf), (pos) + (size)*l); }
00210 
00211 #define SSMBMACRO(macro,buf,pos,val,len,size) \
00212 { int l; for (l = 0; l < (len); l++) macro((buf), (pos) + (size)*l, (val)[l]); }
00213 
00214 /* reads multiple data from an SMB buffer */
00215 #define PCVAL(buf,pos,val,len) SMBMACRO(CVAL,buf,pos,val,len,1)
00216 #define PSVAL(buf,pos,val,len) SMBMACRO(SVAL,buf,pos,val,len,2)
00217 #define PIVAL(buf,pos,val,len) SMBMACRO(IVAL,buf,pos,val,len,4)
00218 #define PCVALS(buf,pos,val,len) SMBMACRO(CVALS,buf,pos,val,len,1)
00219 #define PSVALS(buf,pos,val,len) SMBMACRO(SVALS,buf,pos,val,len,2)
00220 #define PIVALS(buf,pos,val,len) SMBMACRO(IVALS,buf,pos,val,len,4)
00221 
00222 /* stores multiple data in an SMB buffer */
00223 #define PSCVAL(buf,pos,val,len) SSMBMACRO(SCVAL,buf,pos,val,len,1)
00224 #define PSSVAL(buf,pos,val,len) SSMBMACRO(SSVAL,buf,pos,val,len,2)
00225 #define PSIVAL(buf,pos,val,len) SSMBMACRO(SIVAL,buf,pos,val,len,4)
00226 #define PSCVALS(buf,pos,val,len) SSMBMACRO(SCVALS,buf,pos,val,len,1)
00227 #define PSSVALS(buf,pos,val,len) SSMBMACRO(SSVALS,buf,pos,val,len,2)
00228 #define PSIVALS(buf,pos,val,len) SSMBMACRO(SIVALS,buf,pos,val,len,4)
00229 
00230 
00231 /* now the reverse routines - these are used in nmb packets (mostly) */
00232 #define SREV(x) ((((x)&0xFF)<<8) | (((x)>>8)&0xFF))
00233 #define IREV(x) ((SREV(x)<<16) | (SREV((x)>>16)))
00234 
00235 #define RSVAL(buf,pos) SREV(SVAL(buf,pos))
00236 #define RSVALS(buf,pos) SREV(SVALS(buf,pos))
00237 #define RIVAL(buf,pos) IREV(IVAL(buf,pos))
00238 #define RIVALS(buf,pos) IREV(IVALS(buf,pos))
00239 #define RSSVAL(buf,pos,val) SSVAL(buf,pos,SREV(val))
00240 #define RSSVALS(buf,pos,val) SSVALS(buf,pos,SREV(val))
00241 #define RSIVAL(buf,pos,val) SIVAL(buf,pos,IREV(val))
00242 #define RSIVALS(buf,pos,val) SIVALS(buf,pos,IREV(val))
00243 
00244 /* reads multiple data from an SMB buffer (big-endian) */
00245 #define RPSVAL(buf,pos,val,len) SMBMACRO(RSVAL,buf,pos,val,len,2)
00246 #define RPIVAL(buf,pos,val,len) SMBMACRO(RIVAL,buf,pos,val,len,4)
00247 #define RPSVALS(buf,pos,val,len) SMBMACRO(RSVALS,buf,pos,val,len,2)
00248 #define RPIVALS(buf,pos,val,len) SMBMACRO(RIVALS,buf,pos,val,len,4)
00249 
00250 /* stores multiple data in an SMB buffer (big-endian) */
00251 #define RPSSVAL(buf,pos,val,len) SSMBMACRO(RSSVAL,buf,pos,val,len,2)
00252 #define RPSIVAL(buf,pos,val,len) SSMBMACRO(RSIVAL,buf,pos,val,len,4)
00253 #define RPSSVALS(buf,pos,val,len) SSMBMACRO(RSSVALS,buf,pos,val,len,2)
00254 #define RPSIVALS(buf,pos,val,len) SSMBMACRO(RSIVALS,buf,pos,val,len,4)
00255 
00256 #define DBG_RW_PCVAL(charmode,string,depth,base,read,inbuf,outbuf,len) \
00257         { RW_PCVAL(read,inbuf,outbuf,len) \
00258         DEBUG(5,("%s%04x %s: ", \
00259              tab_depth(depth), base,string)); \
00260     if (charmode) print_asc(5, (unsigned char*)(outbuf), (len)); else \
00261         { int idx; for (idx = 0; idx < len; idx++) { DEBUG(5,("%02x ", (outbuf)[idx])); } } \
00262         DEBUG(5,("\n")); } 
00263 
00264 #define DBG_RW_PSVAL(charmode,string,depth,base,read,big_endian,inbuf,outbuf,len) \
00265         { RW_PSVAL(read,big_endian,inbuf,outbuf,len) \
00266         DEBUG(5,("%s%04x %s: ", \
00267              tab_depth(depth), base,string)); \
00268     if (charmode) print_asc(5, (unsigned char*)(outbuf), 2*(len)); else \
00269         { int idx; for (idx = 0; idx < len; idx++) { DEBUG(5,("%04x ", (outbuf)[idx])); } } \
00270         DEBUG(5,("\n")); }
00271 
00272 #define DBG_RW_PIVAL(charmode,string,depth,base,read,big_endian,inbuf,outbuf,len) \
00273         { RW_PIVAL(read,big_endian,inbuf,outbuf,len) \
00274         DEBUG(5,("%s%04x %s: ", \
00275              tab_depth(depth), base,string)); \
00276     if (charmode) print_asc(5, (unsigned char*)(outbuf), 4*(len)); else \
00277         { int idx; for (idx = 0; idx < len; idx++) { DEBUG(5,("%08x ", (outbuf)[idx])); } } \
00278         DEBUG(5,("\n")); }
00279 
00280 #define DBG_RW_CVAL(string,depth,base,read,inbuf,outbuf) \
00281         { RW_CVAL(read,inbuf,outbuf,0) \
00282         DEBUG(5,("%s%04x %s: %02x\n", \
00283              tab_depth(depth), base, string, outbuf)); }
00284 
00285 #define DBG_RW_SVAL(string,depth,base,read,big_endian,inbuf,outbuf) \
00286         { RW_SVAL(read,big_endian,inbuf,outbuf,0) \
00287         DEBUG(5,("%s%04x %s: %04x\n", \
00288              tab_depth(depth), base, string, outbuf)); }
00289 
00290 #define DBG_RW_IVAL(string,depth,base,read,big_endian,inbuf,outbuf) \
00291         { RW_IVAL(read,big_endian,inbuf,outbuf,0) \
00292         DEBUG(5,("%s%04x %s: %08x\n", \
00293              tab_depth(depth), base, string, outbuf)); }
00294 
00295 #endif /* _BYTEORDER_H */
00296 
00297 
00298 /* Samba MD4 implementation */
00299 /* NOTE: This code makes no attempt to be fast! 
00300 
00301    It assumes that a int is at least 32 bits long
00302 */
00303 
00304 static uint32 A, B, C, D;
00305 
00306 static uint32 F(uint32 X, uint32 Y, uint32 Z)
00307 {
00308         return (X&Y) | ((~X)&Z);
00309 }
00310 
00311 static uint32 G(uint32 X, uint32 Y, uint32 Z)
00312 {
00313         return (X&Y) | (X&Z) | (Y&Z); 
00314 }
00315 
00316 static uint32 H(uint32 X, uint32 Y, uint32 Z)
00317 {
00318         return X^Y^Z;
00319 }
00320 
00321 static uint32 lshift(uint32 x, int s)
00322 {
00323         x &= 0xFFFFFFFF;
00324         return ((x<<s)&0xFFFFFFFF) | (x>>(32-s));
00325 }
00326 
00327 #define ROUND1(a,b,c,d,k,s) a = lshift(a + F(b,c,d) + X[k], s)
00328 #define ROUND2(a,b,c,d,k,s) a = lshift(a + G(b,c,d) + X[k] + (uint32)0x5A827999,s)
00329 #define ROUND3(a,b,c,d,k,s) a = lshift(a + H(b,c,d) + X[k] + (uint32)0x6ED9EBA1,s)
00330 
00331 /* this applies md4 to 64 byte chunks */
00332 static void mdfour64(uint32 *M)
00333 {
00334         int j;
00335         uint32 AA, BB, CC, DD;
00336         uint32 X[16];
00337 
00338         for (j=0;j<16;j++)
00339                 X[j] = M[j];
00340 
00341         AA = A; BB = B; CC = C; DD = D;
00342 
00343         ROUND1(A,B,C,D,  0,  3);  ROUND1(D,A,B,C,  1,  7);  
00344         ROUND1(C,D,A,B,  2, 11);  ROUND1(B,C,D,A,  3, 19);
00345         ROUND1(A,B,C,D,  4,  3);  ROUND1(D,A,B,C,  5,  7);  
00346         ROUND1(C,D,A,B,  6, 11);  ROUND1(B,C,D,A,  7, 19);
00347         ROUND1(A,B,C,D,  8,  3);  ROUND1(D,A,B,C,  9,  7);  
00348         ROUND1(C,D,A,B, 10, 11);  ROUND1(B,C,D,A, 11, 19);
00349         ROUND1(A,B,C,D, 12,  3);  ROUND1(D,A,B,C, 13,  7);  
00350         ROUND1(C,D,A,B, 14, 11);  ROUND1(B,C,D,A, 15, 19);      
00351 
00352         ROUND2(A,B,C,D,  0,  3);  ROUND2(D,A,B,C,  4,  5);  
00353         ROUND2(C,D,A,B,  8,  9);  ROUND2(B,C,D,A, 12, 13);
00354         ROUND2(A,B,C,D,  1,  3);  ROUND2(D,A,B,C,  5,  5);  
00355         ROUND2(C,D,A,B,  9,  9);  ROUND2(B,C,D,A, 13, 13);
00356         ROUND2(A,B,C,D,  2,  3);  ROUND2(D,A,B,C,  6,  5);  
00357         ROUND2(C,D,A,B, 10,  9);  ROUND2(B,C,D,A, 14, 13);
00358         ROUND2(A,B,C,D,  3,  3);  ROUND2(D,A,B,C,  7,  5);  
00359         ROUND2(C,D,A,B, 11,  9);  ROUND2(B,C,D,A, 15, 13);
00360 
00361         ROUND3(A,B,C,D,  0,  3);  ROUND3(D,A,B,C,  8,  9);  
00362         ROUND3(C,D,A,B,  4, 11);  ROUND3(B,C,D,A, 12, 15);
00363         ROUND3(A,B,C,D,  2,  3);  ROUND3(D,A,B,C, 10,  9);  
00364         ROUND3(C,D,A,B,  6, 11);  ROUND3(B,C,D,A, 14, 15);
00365         ROUND3(A,B,C,D,  1,  3);  ROUND3(D,A,B,C,  9,  9);  
00366         ROUND3(C,D,A,B,  5, 11);  ROUND3(B,C,D,A, 13, 15);
00367         ROUND3(A,B,C,D,  3,  3);  ROUND3(D,A,B,C, 11,  9);  
00368         ROUND3(C,D,A,B,  7, 11);  ROUND3(B,C,D,A, 15, 15);
00369 
00370         A += AA; B += BB; C += CC; D += DD;
00371         
00372         A &= 0xFFFFFFFF; B &= 0xFFFFFFFF;
00373         C &= 0xFFFFFFFF; D &= 0xFFFFFFFF;
00374 
00375         for (j=0;j<16;j++)
00376                 X[j] = 0;
00377 }
00378 
00379 static void copy64(uint32 *M, unsigned char *in)
00380 {
00381         int i;
00382 
00383         for (i=0;i<16;i++)
00384                 M[i] = (in[i*4+3]<<24) | (in[i*4+2]<<16) |
00385                         (in[i*4+1]<<8) | (in[i*4+0]<<0);
00386 }
00387 
00388 static void copy4(unsigned char *out,uint32 x)
00389 {
00390         out[0] = x&0xFF;
00391         out[1] = (x>>8)&0xFF;
00392         out[2] = (x>>16)&0xFF;
00393         out[3] = (x>>24)&0xFF;
00394 }
00395 
00396 /* produce a md4 message digest from data of length n bytes */
00397 void mdfour(unsigned char *out, unsigned char *in, int n)
00398 {
00399         unsigned char buf[128];
00400         uint32 M[16];
00401         uint32 b = n * 8;
00402         int i;
00403 
00404         A = 0x67452301;
00405         B = 0xefcdab89;
00406         C = 0x98badcfe;
00407         D = 0x10325476;
00408 
00409         while (n > 64) {
00410                 copy64(M, in);
00411                 mdfour64(M);
00412                 in += 64;
00413                 n -= 64;
00414         }
00415 
00416         for (i=0;i<128;i++)
00417                 buf[i] = 0;
00418         memcpy(buf, in, n);
00419         buf[n] = 0x80;
00420         
00421         if (n <= 55) {
00422                 copy4(buf+56, b);
00423                 copy64(M, buf);
00424                 mdfour64(M);
00425         } else {
00426                 copy4(buf+120, b); 
00427                 copy64(M, buf);
00428                 mdfour64(M);
00429                 copy64(M, buf+64);
00430                 mdfour64(M);
00431         }
00432 
00433         for (i=0;i<128;i++)
00434                 buf[i] = 0;
00435         copy64(M, buf);
00436 
00437         copy4(out, A);
00438         copy4(out+4, B);
00439         copy4(out+8, C);
00440         copy4(out+12, D);
00441 
00442         A = B = C = D = 0;
00443 }
00444 
00445 
00446 /* Samba DES implementation */
00447 #define uchar unsigned char
00448 #define int16 signed short
00449 typedef int BOOL;
00450 #define False 0
00451 #define True  1
00452 
00453 static uchar perm1[56] = {57, 49, 41, 33, 25, 17,  9,
00454                          1, 58, 50, 42, 34, 26, 18,
00455                         10,  2, 59, 51, 43, 35, 27,
00456                         19, 11,  3, 60, 52, 44, 36,
00457                         63, 55, 47, 39, 31, 23, 15,
00458                          7, 62, 54, 46, 38, 30, 22,
00459                         14,  6, 61, 53, 45, 37, 29,
00460                         21, 13,  5, 28, 20, 12,  4};
00461 
00462 static uchar perm2[48] = {14, 17, 11, 24,  1,  5,
00463                          3, 28, 15,  6, 21, 10,
00464                         23, 19, 12,  4, 26,  8,
00465                         16,  7, 27, 20, 13,  2,
00466                         41, 52, 31, 37, 47, 55,
00467                         30, 40, 51, 45, 33, 48,
00468                         44, 49, 39, 56, 34, 53,
00469                         46, 42, 50, 36, 29, 32};
00470 
00471 static uchar perm3[64] = {58, 50, 42, 34, 26, 18, 10,  2,
00472                         60, 52, 44, 36, 28, 20, 12,  4,
00473                         62, 54, 46, 38, 30, 22, 14,  6,
00474                         64, 56, 48, 40, 32, 24, 16,  8,
00475                         57, 49, 41, 33, 25, 17,  9,  1,
00476                         59, 51, 43, 35, 27, 19, 11,  3,
00477                         61, 53, 45, 37, 29, 21, 13,  5,
00478                         63, 55, 47, 39, 31, 23, 15,  7};
00479 
00480 static uchar perm4[48] = {   32,  1,  2,  3,  4,  5,
00481                             4,  5,  6,  7,  8,  9,
00482                             8,  9, 10, 11, 12, 13,
00483                            12, 13, 14, 15, 16, 17,
00484                            16, 17, 18, 19, 20, 21,
00485                            20, 21, 22, 23, 24, 25,
00486                            24, 25, 26, 27, 28, 29,
00487                            28, 29, 30, 31, 32,  1};
00488 
00489 static uchar perm5[32] = {      16,  7, 20, 21,
00490                               29, 12, 28, 17,
00491                                1, 15, 23, 26,
00492                                5, 18, 31, 10,
00493                                2,  8, 24, 14,
00494                               32, 27,  3,  9,
00495                               19, 13, 30,  6,
00496                               22, 11,  4, 25};
00497 
00498 
00499 static uchar perm6[64] ={ 40,  8, 48, 16, 56, 24, 64, 32,
00500                         39,  7, 47, 15, 55, 23, 63, 31,
00501                         38,  6, 46, 14, 54, 22, 62, 30,
00502                         37,  5, 45, 13, 53, 21, 61, 29,
00503                         36,  4, 44, 12, 52, 20, 60, 28,
00504                         35,  3, 43, 11, 51, 19, 59, 27,
00505                         34,  2, 42, 10, 50, 18, 58, 26,
00506                         33,  1, 41,  9, 49, 17, 57, 25};
00507 
00508 
00509 static uchar sc[16] = {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};
00510 
00511 static uchar sbox[8][4][16] = {
00512         {{14,  4, 13,  1,  2, 15, 11,  8,  3, 10,  6, 12,  5,  9,  0,  7},
00513          {0, 15,  7,  4, 14,  2, 13,  1, 10,  6, 12, 11,  9,  5,  3,  8},
00514          {4,  1, 14,  8, 13,  6,  2, 11, 15, 12,  9,  7,  3, 10,  5,  0},
00515          {15, 12,  8,  2,  4,  9,  1,  7,  5, 11,  3, 14, 10,  0,  6, 13}},
00516 
00517         {{15,  1,  8, 14,  6, 11,  3,  4,  9,  7,  2, 13, 12,  0,  5, 10},
00518          {3, 13,  4,  7, 15,  2,  8, 14, 12,  0,  1, 10,  6,  9, 11,  5},
00519          {0, 14,  7, 11, 10,  4, 13,  1,  5,  8, 12,  6,  9,  3,  2, 15},
00520          {13,  8, 10,  1,  3, 15,  4,  2, 11,  6,  7, 12,  0,  5, 14,  9}},
00521 
00522         {{10,  0,  9, 14,  6,  3, 15,  5,  1, 13, 12,  7, 11,  4,  2,  8},
00523          {13,  7,  0,  9,  3,  4,  6, 10,  2,  8,  5, 14, 12, 11, 15,  1},
00524          {13,  6,  4,  9,  8, 15,  3,  0, 11,  1,  2, 12,  5, 10, 14,  7},
00525          {1, 10, 13,  0,  6,  9,  8,  7,  4, 15, 14,  3, 11,  5,  2, 12}},
00526 
00527         {{7, 13, 14,  3,  0,  6,  9, 10,  1,  2,  8,  5, 11, 12,  4, 15},
00528          {13,  8, 11,  5,  6, 15,  0,  3,  4,  7,  2, 12,  1, 10, 14,  9},
00529          {10,  6,  9,  0, 12, 11,  7, 13, 15,  1,  3, 14,  5,  2,  8,  4},
00530          {3, 15,  0,  6, 10,  1, 13,  8,  9,  4,  5, 11, 12,  7,  2, 14}},
00531 
00532         {{2, 12,  4,  1,  7, 10, 11,  6,  8,  5,  3, 15, 13,  0, 14,  9},
00533          {14, 11,  2, 12,  4,  7, 13,  1,  5,  0, 15, 10,  3,  9,  8,  6},
00534          {4,  2,  1, 11, 10, 13,  7,  8, 15,  9, 12,  5,  6,  3,  0, 14},
00535          {11,  8, 12,  7,  1, 14,  2, 13,  6, 15,  0,  9, 10,  4,  5,  3}},
00536 
00537         {{12,  1, 10, 15,  9,  2,  6,  8,  0, 13,  3,  4, 14,  7,  5, 11},
00538          {10, 15,  4,  2,  7, 12,  9,  5,  6,  1, 13, 14,  0, 11,  3,  8},
00539          {9, 14, 15,  5,  2,  8, 12,  3,  7,  0,  4, 10,  1, 13, 11,  6},
00540          {4,  3,  2, 12,  9,  5, 15, 10, 11, 14,  1,  7,  6,  0,  8, 13}},
00541 
00542         {{4, 11,  2, 14, 15,  0,  8, 13,  3, 12,  9,  7,  5, 10,  6,  1},
00543          {13,  0, 11,  7,  4,  9,  1, 10, 14,  3,  5, 12,  2, 15,  8,  6},
00544          {1,  4, 11, 13, 12,  3,  7, 14, 10, 15,  6,  8,  0,  5,  9,  2},
00545          {6, 11, 13,  8,  1,  4, 10,  7,  9,  5,  0, 15, 14,  2,  3, 12}},
00546 
00547         {{13,  2,  8,  4,  6, 15, 11,  1, 10,  9,  3, 14,  5,  0, 12,  7},
00548          {1, 15, 13,  8, 10,  3,  7,  4, 12,  5,  6, 11,  0, 14,  9,  2},
00549          {7, 11,  4,  1,  9, 12, 14,  2,  0,  6, 10, 13, 15,  3,  5,  8},
00550          {2,  1, 14,  7,  4, 10,  8, 13, 15, 12,  9,  0,  3,  5,  6, 11}}};
00551 
00552 static void permute(char *out, char *in, uchar *p, int n)
00553 {
00554         int i;
00555         for (i=0;i<n;i++)
00556                 out[i] = in[p[i]-1];
00557 }
00558 
00559 static void l_shift(char *d, int count, int n)
00560 {
00561         char out[64];
00562         int i;
00563         for (i=0;i<n;i++)
00564                 out[i] = d[(i+count)%n];
00565         for (i=0;i<n;i++)
00566                 d[i] = out[i];
00567 }
00568 
00569 static void concat(char *out, char *in1, char *in2, int l1, int l2)
00570 {
00571         while (l1--)
00572                 *out++ = *in1++;
00573         while (l2--)
00574                 *out++ = *in2++;
00575 }
00576 
00577 static void xorFunction(char *out, char *in1, char *in2, int n)
00578 {
00579 
00580         int i;
00581         for (i=0; i < n; i++)
00582                 out[i] = in1[i] ^ in2[i];
00583 
00584 }
00585 
00586 static void dohash(char *out, char *in, char *key, int forw)
00587 {
00588         int i, j, k;
00589         char pk1[56];
00590         char c[28];
00591         char d[28];
00592         char cd[56];
00593         char ki[16][48];
00594         char pd1[64];
00595         char l[32], r[32];
00596         char rl[64];
00597 
00598 
00599         permute(pk1, key, perm1, 56);
00600 
00601         for (i=0;i<28;i++)
00602                 c[i] = pk1[i];
00603         for (i=0;i<28;i++)
00604                 d[i] = pk1[i+28];
00605 
00606         for (i=0;i<16;i++) {
00607                 l_shift(c, sc[i], 28);
00608                 l_shift(d, sc[i], 28);
00609 
00610                 concat(cd, c, d, 28, 28); 
00611                 permute(ki[i], cd, perm2, 48); 
00612         }
00613 
00614         permute(pd1, in, perm3, 64);
00615 
00616         for (j=0;j<32;j++) {
00617                 l[j] = pd1[j];
00618                 r[j] = pd1[j+32];
00619         }
00620 
00621         for (i=0;i<16;i++) {
00622                 char er[48];
00623                 char erk[48];
00624                 char b[8][6];
00625                 char cb[32];
00626                 char pcb[32];
00627                 char r2[32];
00628 
00629                 permute(er, r, perm4, 48);
00630 
00631                 xorFunction(erk, er, ki[(forw ? i : 15 - i)], 48);
00632 
00633                 for (j=0;j<8;j++)
00634                         for (k=0;k<6;k++)
00635                                 b[j][k] = erk[j*6 + k];
00636 
00637                 for (j=0;j<8;j++) {
00638                         int m, n;
00639                         m = (b[j][0]<<1) | b[j][5];
00640 
00641                         n = (b[j][1]<<3) | (b[j][2]<<2) | (b[j][3]<<1) | b[j][4]; 
00642 
00643                         for (k=0;k<4;k++) 
00644                                 b[j][k] = (sbox[j][m][n] & (1<<(3-k)))?1:0; 
00645                 }
00646 
00647                 for (j=0;j<8;j++)
00648                         for (k=0;k<4;k++)
00649                                 cb[j*4+k] = b[j][k];
00650 
00651                 permute(pcb, cb, perm5, 32);
00652 
00653                 xorFunction( r2, l, pcb, 32);
00654 
00655                 for (j=0;j<32;j++)
00656                         l[j] = r[j];
00657 
00658                 for (j=0;j<32;j++)
00659                         r[j] = r2[j];
00660         }
00661 
00662         concat(rl, r, l, 32, 32);
00663 
00664         permute(out, rl, perm6, 64);
00665 }
00666 
00667 static void str_to_key(unsigned char *str,unsigned char *key)
00668 {
00669         int i;
00670 
00671         key[0] = str[0]>>1;
00672         key[1] = ((str[0]&0x01)<<6) | (str[1]>>2);
00673         key[2] = ((str[1]&0x03)<<5) | (str[2]>>3);
00674         key[3] = ((str[2]&0x07)<<4) | (str[3]>>4);
00675         key[4] = ((str[3]&0x0F)<<3) | (str[4]>>5);
00676         key[5] = ((str[4]&0x1F)<<2) | (str[5]>>6);
00677         key[6] = ((str[5]&0x3F)<<1) | (str[6]>>7);
00678         key[7] = str[6]&0x7F;
00679         for (i=0;i<8;i++) {
00680                 key[i] = (key[i]<<1);
00681         }
00682 }
00683 
00684 
00685 static void smbhash(unsigned char *out, unsigned char *in, unsigned char *key, int forw)
00686 {
00687         int i;
00688         char outb[64];
00689         char inb[64];
00690         char keyb[64];
00691         unsigned char key2[8];
00692 
00693         str_to_key(key, key2);
00694 
00695         for (i=0;i<64;i++) {
00696                 inb[i] = (in[i/8] & (1<<(7-(i%8)))) ? 1 : 0;
00697                 keyb[i] = (key2[i/8] & (1<<(7-(i%8)))) ? 1 : 0;
00698                 outb[i] = 0;
00699         }
00700 
00701         dohash(outb, inb, keyb, forw);
00702 
00703         for (i=0;i<8;i++) {
00704                 out[i] = 0;
00705         }
00706 
00707         for (i=0;i<64;i++) {
00708                 if (outb[i])
00709                         out[i/8] |= (1<<(7-(i%8)));
00710         }
00711 }
00712 
00713 void E_P16(unsigned char *p14,unsigned char *p16)
00714 {
00715         unsigned char sp8[8] = {0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25};
00716         smbhash(p16, sp8, p14, 1);
00717         smbhash(p16+8, sp8, p14+7, 1);
00718 }
00719 
00720 void E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24)
00721 {
00722         smbhash(p24, c8, p21, 1);
00723         smbhash(p24+8, c8, p21+7, 1);
00724         smbhash(p24+16, c8, p21+14, 1);
00725 }
00726 
00727 void D_P16(unsigned char *p14, unsigned char *in, unsigned char *out)
00728 {
00729         smbhash(out, in, p14, 0);
00730         smbhash(out+8, in+8, p14+7, 0);
00731 }
00732 
00733 void E_old_pw_hash( unsigned char *p14, unsigned char *in, unsigned char *out)
00734 {
00735         smbhash(out, in, p14, 1);
00736         smbhash(out+8, in+8, p14+7, 1);
00737 }
00738 
00739 void cred_hash1(unsigned char *out,unsigned char *in,unsigned char *key)
00740 {
00741         unsigned char buf[8];
00742 
00743         smbhash(buf, in, key, 1);
00744         smbhash(out, buf, key+9, 1);
00745 }
00746 
00747 void cred_hash2(unsigned char *out,unsigned char *in,unsigned char *key)
00748 {
00749         unsigned char buf[8];
00750         static unsigned char key2[8];
00751 
00752         smbhash(buf, in, key, 1);
00753         key2[0] = key[7];
00754         smbhash(out, buf, key2, 1);
00755 }
00756 
00757 void cred_hash3(unsigned char *out,unsigned char *in,unsigned char *key, int forw)
00758 {
00759         static unsigned char key2[8];
00760 
00761         smbhash(out, in, key, forw);
00762         key2[0] = key[7];
00763         smbhash(out + 8, in + 8, key2, forw);
00764 }
00765 
00766 void SamOEMhash( unsigned char *data, unsigned char *key, int val)
00767 {
00768   unsigned char s_box[256];
00769   unsigned char index_i = 0;
00770   unsigned char index_j = 0;
00771   unsigned char j = 0;
00772   int ind;
00773 
00774   for (ind = 0; ind < 256; ind++)
00775   {
00776     s_box[ind] = (unsigned char)ind;
00777   }
00778 
00779   for( ind = 0; ind < 256; ind++)
00780   {
00781      unsigned char tc;
00782 
00783      j += (s_box[ind] + key[ind%16]);
00784 
00785      tc = s_box[ind];
00786      s_box[ind] = s_box[j];
00787      s_box[j] = tc;
00788   }
00789   for( ind = 0; ind < (val ? 516 : 16); ind++)
00790   {
00791     unsigned char tc;
00792     unsigned char t;
00793 
00794     index_i++;
00795     index_j += s_box[index_i];
00796 
00797     tc = s_box[index_i];
00798     s_box[index_i] = s_box[index_j];
00799     s_box[index_j] = tc;
00800 
00801     t = s_box[index_i] + s_box[index_j];
00802     data[ind] = data[ind] ^ s_box[t];
00803   }
00804 }
00805 
00806 /* Samba encryption implementation*/
00807 
00808 
00809 /****************************************************************************
00810  Like strncpy but always null terminates. Make sure there is room!
00811  The variable n should always be one less than the available size.
00812 ****************************************************************************/
00813 
00814 char *StrnCpy(char *dest,const char *src, size_t n)
00815 {
00816   char *d = dest;
00817   if (!dest) return(NULL);
00818   if (!src) {
00819     *dest = 0;
00820     return(dest);
00821   }
00822   while (n-- && (*d++ = *src++)) ;
00823   *d = 0;
00824   return(dest);
00825 }
00826 
00827 size_t skip_multibyte_char(char c)
00828 {
00829 return 0;
00830 }
00831 
00832 
00833 /*******************************************************************
00834 safe string copy into a known length string. maxlength does not
00835 include the terminating zero.
00836 ********************************************************************/
00837 #define DEBUG(a,b) ;
00838 char *safe_strcpy(char *dest,const char *src, size_t maxlength)
00839 {
00840     size_t len;
00841 
00842     if (!dest) {
00843         DEBUG(0,("ERROR: NULL dest in safe_strcpy\n"));
00844         return NULL;
00845     }
00846 
00847     if (!src) {
00848         *dest = 0;
00849         return dest;
00850     }  
00851 
00852     len = strlen(src);
00853 
00854     if (len > maxlength) {
00855             DEBUG(0,("ERROR: string overflow by %d in safe_strcpy [%.50s]\n",
00856                      (int)(len-maxlength), src));
00857             len = maxlength;
00858     }
00859       
00860     memcpy(dest, src, len);
00861     dest[len] = 0;
00862     return dest;
00863 }  
00864 
00865 
00866 void strupper(char *s)
00867 {
00868 while (*s)
00869   {
00870     {
00871     size_t skip = skip_multibyte_char( *s );
00872     if( skip != 0 )
00873       s += skip;
00874     else
00875       {
00876       if (islower(*s))
00877         *s = toupper(*s);
00878       s++;
00879       }
00880     }
00881   }
00882 }
00883 
00884 extern void SMBOWFencrypt(uchar passwd[16], uchar *c8, uchar p24[24]);
00885 
00886 /*
00887  This implements the X/Open SMB password encryption
00888  It takes a password, a 8 byte "crypt key" and puts 24 bytes of 
00889  encrypted password into p24 
00890  */
00891 
00892 void SMBencrypt(uchar *passwd, uchar *c8, uchar *p24)
00893   {
00894   uchar p14[15], p21[21];
00895   
00896   memset(p21,'\0',21);
00897   memset(p14,'\0',14);
00898   StrnCpy((char *)p14,(char *)passwd,14);
00899   
00900   strupper((char *)p14);
00901   E_P16(p14, p21); 
00902   
00903   SMBOWFencrypt(p21, c8, p24);
00904   
00905 #ifdef DEBUG_PASSWORD
00906   DEBUG(100,("SMBencrypt: lm#, challenge, response\n"));
00907   dump_data(100, (char *)p21, 16);
00908   dump_data(100, (char *)c8, 8);
00909   dump_data(100, (char *)p24, 24);
00910 #endif
00911   }
00912 
00913 /* Routines for Windows NT MD4 Hash functions. */
00914 static int _my_wcslen(int16 *str)
00915 {
00916         int len = 0;
00917         while(*str++ != 0)
00918                 len++;
00919         return len;
00920 }
00921 
00922 /*
00923  * Convert a string into an NT UNICODE string.
00924  * Note that regardless of processor type 
00925  * this must be in intel (little-endian)
00926  * format.
00927  */
00928  
00929 static int _my_mbstowcs(int16 *dst, uchar *src, int len)
00930 {
00931         int i;
00932         int16 val;
00933  
00934         for(i = 0; i < len; i++) {
00935                 val = *src;
00936                 SSVAL(dst,0,val);
00937                 dst++;
00938                 src++;
00939                 if(val == 0)
00940                         break;
00941         }
00942         return i;
00943 }
00944 
00945 /* 
00946  * Creates the MD4 Hash of the users password in NT UNICODE.
00947  */
00948  
00949 void E_md4hash(uchar *passwd, uchar *p16)
00950 {
00951         int len;
00952         int16 wpwd[129];
00953         
00954         /* Password cannot be longer than 128 characters */
00955         len = (int) strlen((char *)passwd);
00956         if(len > 128)
00957                 len = 128;
00958         /* Password must be converted to NT unicode */
00959         _my_mbstowcs(wpwd, passwd, len);
00960         wpwd[len] = 0; /* Ensure string is null terminated */
00961         /* Calculate length in bytes */
00962         len = _my_wcslen(wpwd) * sizeof(int16);
00963 
00964         mdfour(p16, (unsigned char *)wpwd, len);
00965 }
00966 
00967 /* Does both the NT and LM owfs of a user's password */
00968 void nt_lm_owf_gen(char *pwd, uchar nt_p16[16], uchar p16[16])
00969 {
00970         char passwd[130];
00971 
00972         memset(passwd,'\0',130);
00973         safe_strcpy( passwd, pwd, sizeof(passwd)-1);
00974 
00975         /* Calculate the MD4 hash (NT compatible) of the password */
00976         memset(nt_p16, '\0', 16);
00977         E_md4hash((uchar *)passwd, nt_p16);
00978 
00979 #ifdef DEBUG_PASSWORD
00980         DEBUG(100,("nt_lm_owf_gen: pwd, nt#\n"));
00981         dump_data(120, passwd, strlen(passwd));
00982         dump_data(100, (char *)nt_p16, 16);
00983 #endif
00984 
00985         /* Mangle the passwords into Lanman format */
00986         passwd[14] = '\0';
00987         strupper(passwd);
00988 
00989         /* Calculate the SMB (lanman) hash functions of the password */
00990 
00991         memset(p16, '\0', 16);
00992         E_P16((uchar *) passwd, (uchar *)p16);
00993 
00994 #ifdef DEBUG_PASSWORD
00995         DEBUG(100,("nt_lm_owf_gen: pwd, lm#\n"));
00996         dump_data(120, passwd, strlen(passwd));
00997         dump_data(100, (char *)p16, 16);
00998 #endif
00999         /* clear out local copy of user's password (just being paranoid). */
01000         memset(passwd, '\0', sizeof(passwd));
01001 }
01002 
01003 /* Does the des encryption from the NT or LM MD4 hash. */
01004 void SMBOWFencrypt(uchar passwd[16], uchar *c8, uchar p24[24])
01005 {
01006         uchar p21[21];
01007  
01008         memset(p21,'\0',21);
01009  
01010         memcpy(p21, passwd, 16);    
01011         E_P24(p21, c8, p24);
01012 }
01013 
01014 /* Does the des encryption from the FIRST 8 BYTES of the NT or LM MD4 hash. */
01015 void NTLMSSPOWFencrypt(uchar passwd[8], uchar *ntlmchalresp, uchar p24[24])
01016 {
01017         uchar p21[21];
01018  
01019         memset(p21,'\0',21);
01020         memcpy(p21, passwd, 8);    
01021         memset(p21 + 8, 0xbd, 8);    
01022 
01023         E_P24(p21, ntlmchalresp, p24);
01024 #ifdef DEBUG_PASSWORD
01025         DEBUG(100,("NTLMSSPOWFencrypt: p21, c8, p24\n"));
01026         dump_data(100, (char *)p21, 21);
01027         dump_data(100, (char *)ntlmchalresp, 8);
01028         dump_data(100, (char *)p24, 24);
01029 #endif
01030 }
01031 
01032 
01033 /* Does the NT MD4 hash then des encryption. */
01034  
01035 void SMBNTencrypt(uchar *passwd, uchar *c8, uchar *p24)
01036 {
01037         uchar p21[21];
01038  
01039         memset(p21,'\0',21);
01040  
01041         E_md4hash(passwd, p21);    
01042         SMBOWFencrypt(p21, c8, p24);
01043 
01044 #ifdef DEBUG_PASSWORD
01045         DEBUG(100,("SMBNTencrypt: nt#, challenge, response\n"));
01046         dump_data(100, (char *)p21, 16);
01047         dump_data(100, (char *)c8, 8);
01048         dump_data(100, (char *)p24, 24);
01049 #endif
01050 }
01051 
01052 #if 0
01053 
01054 BOOL make_oem_passwd_hash(char data[516], const char *passwd, uchar old_pw_hash[16], BOOL unicode)
01055 {
01056         int new_pw_len = strlen(passwd) * (unicode ? 2 : 1);
01057 
01058         if (new_pw_len > 512)
01059         {
01060                 DEBUG(0,("make_oem_passwd_hash: new password is too long.\n"));
01061                 return False;
01062         }
01063 
01064         /*
01065          * Now setup the data area.
01066          * We need to generate a random fill
01067          * for this area to make it harder to
01068          * decrypt. JRA.
01069          */
01070         generate_random_buffer((unsigned char *)data, 516, False);
01071         if (unicode)
01072         {
01073                 struni2( &data[512 - new_pw_len], passwd);
01074         }
01075         else
01076         {
01077                 fstrcpy( &data[512 - new_pw_len], passwd);
01078         }
01079         SIVAL(data, 512, new_pw_len);
01080 
01081 #ifdef DEBUG_PASSWORD
01082         DEBUG(100,("make_oem_passwd_hash\n"));
01083         dump_data(100, data, 516);
01084 #endif
01085         SamOEMhash( (unsigned char *)data, (unsigned char *)old_pw_hash, True);
01086 
01087         return True;
01088 }
01089 
01090 #endif
01091 
01092 /* libtnlm copyrigth was left here, anyway the interface was slightly modified */
01093 /* included libntlm-3.2.9 (c) even if this code is based in 2.1 version*/
01094 /*
01095 Libntlm AUTHORS -- information about the authors
01096 Copyright (C) 2002, 2003, 2004 Simon Josefsson
01097 See the end for copying conditions.
01098 
01099 Grant Edwards <[email protected]>
01100 Original author of libntlm
01101 
01102 Andrew Tridgell
01103 Wrote functions borrowed from SMB.
01104 
01105 Simon Josefsson <[email protected]>
01106 Build environment, maintainer.
01107 
01108 Frediano Ziglio
01109 Contributed LGPL versions of some of the GPL'd Samba files.
01110 */
01111 
01112 /* The [IS]VAL macros are to take care of byte order for non-Intel
01113  * Machines -- I think this file is OK, but it hasn't been tested.
01114  * The other files (the ones stolen from Samba) should be OK.
01115  * I am not crazy about these macros -- they seem to have gotten
01116  * a bit complex.  A new scheme for handling string/buffer fields
01117  * in the structures probably needs to be designed
01118  */
01119 
01120 
01121 /*SIVAL(&ptr->header.offset,0,((ptr->buffer - ((uint8*)ptr)) + ptr->bufIndex)); \*/
01122 
01123 #define AddBytes(ptr, header, buf, count) \
01124 { \
01125 if (buf && count) \
01126   { \
01127   SSVAL(&ptr->header.len,0,count); \
01128   SSVAL(&ptr->header.maxlen,0,count); \
01129   SIVAL(&ptr->header.offset,0,((ptr->buffer - ((uint8*)ptr)) + ptr->bufIndex)); \
01130   memcpy(ptr->buffer+ptr->bufIndex, buf, count); \
01131   ptr->bufIndex += count; \
01132   } \
01133 else \
01134   { \
01135   ptr->header.len = \
01136   ptr->header.maxlen = 0; \
01137   SIVAL(&ptr->header.offset,0,ptr->bufIndex); \
01138   } \
01139 }
01140 
01141 #define AddString(ptr, header, string) \
01142 { \
01143 char *p = string; \
01144 int len = 0; \
01145 if (p) len = strlen(p); \
01146 AddBytes(ptr, header, ((unsigned char*)p), len); \
01147 }
01148 
01149 #define AddUnicodeString(ptr, header, string) \
01150 { \
01151 char *p = string; \
01152 unsigned char *b = NULL; \
01153 int len = 0; \
01154 if (p) \
01155   { \
01156   len = strlen(p); \
01157   b = strToUnicode(p); \
01158   } \
01159 AddBytes(ptr, header, b, len*2); \
01160 }
01161 
01162 
01163 #define GetUnicodeString(structPtr, header) \
01164 unicodeToString(((char*)structPtr) + IVAL(&structPtr->header.offset,0) , SVAL(&structPtr->header.len,0)/2)
01165 #define GetString(structPtr, header) \
01166 toString((((char *)structPtr) + IVAL(&structPtr->header.offset,0)), SVAL(&structPtr->header.len,0))
01167 #define DumpBuffer(fp, structPtr, header) \
01168 dumpRaw(fp,((unsigned char*)structPtr)+IVAL(&structPtr->header.offset,0),SVAL(&structPtr->header.len,0))
01169 
01170 
01171 static void dumpRaw(FILE *fp, unsigned char *buf, size_t len)
01172   {
01173   int i;
01174   
01175   for (i=0; i<(signed int)len; ++i)
01176     printf("%02x ",buf[i]);
01177     
01178     printf("\n");
01179   }
01180 
01181 static char *unicodeToString(char *p, size_t len)
01182   {
01183   int i;
01184   static char buf[16384];
01185 
01186   assert(len+1 < sizeof buf);
01187   
01188   for (i=0; i<(signed int)len; ++i)
01189     {  
01190     buf[i] = *p & 0x7f;
01191     p += 2;
01192     }
01193 
01194   buf[i] = '\0';
01195   return buf;
01196   }
01197 
01198 static unsigned char *strToUnicode(char *p)
01199   {
01200   static unsigned char buf[16384];
01201   size_t l = strlen(p);
01202   int i = 0;
01203   
01204   assert(l*2 < sizeof buf);
01205   
01206   while (l--)
01207     {
01208     buf[i++] = *p++;
01209     buf[i++] = 0;
01210     }
01211   
01212   return buf;
01213   }
01214 
01215 static unsigned char *toString(char *p, size_t len)
01216   {
01217   static unsigned char buf[16384];
01218   
01219   assert(len+1 < sizeof buf);
01220   
01221   memcpy(buf,p,len);
01222   buf[len] = 0;
01223   return buf;
01224   }
01225 
01226 
01227 
01228 
01229 void BuildAuthRequest(tSmbNtlmAuthRequest *request, long flags, char *host, char *domain)
01230   {
01231     char *h = NULL;//strdup(host);
01232     char *p = NULL;//strchr(h,'@');
01233         //TODO: review default flags
01234 
01235     if (host == NULL)   host = "";
01236     if (domain == NULL) domain = "";
01237 
01238     h = _strdup(host);
01239     p = strchr(h,'@');
01240     if (p)
01241       {
01242         if (!domain) 
01243           domain = p+1;
01244         *p = '\0';
01245       }
01246     if (flags ==0) flags = 0x0000b207; /* Lowest security options to avoid negotiation */
01247     request->bufIndex = 0;
01248     memcpy(request->ident,"NTLMSSP\0\0\0",8);
01249     SIVAL(&request->msgType,0,1);
01250     SIVAL(&request->flags,0,flags);  
01251         
01252         assert(strlen(host) < 128);
01253     AddString(request,host,h);
01254         assert(strlen(domain) < 128);
01255     AddString(request,domain,domain);
01256     free(h);
01257   }
01258 
01259  #include <openssl/md4.h> //MD4_CTX
01260  #include <openssl/des.h> //des_key_schedule
01261  #ifdef WIN32
01262   #pragma comment(lib, "libeay32.lib")
01263   #pragma comment(lib, "ssleay32.lib")
01264  #endif
01265 
01266 /*
01267 * turns a 56 bit key into the 64 bit, odd parity key and sets the key.
01268 * The key schedule ks is also set.
01269 */
01270 void setup_des_key(unsigned char key_56[], des_key_schedule ksch){
01271 des_cblock key;
01272 
01273         key[0] = key_56[0];
01274         key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
01275         key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
01276         key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
01277         key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
01278         key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
01279         key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
01280         key[7] =  (key_56[6] << 1) & 0xFF;
01281 
01282         des_set_odd_parity(&key);
01283         des_set_key(&key, ksch);
01284 }
01285 
01286   /*
01287  * takes a 21 byte array and treats it as 3 56-bit DES keys. The
01288  * 8 byte plaintext is encrypted with each key and the resulting 24
01289  * bytes are stored in the results array.
01290  */
01291 void calc_resp(unsigned char *keys, unsigned char *plaintext, unsigned char *results){
01292 des_key_schedule ks;
01293 
01294         setup_des_key(keys, ks);
01295         des_ecb_encrypt((des_cblock*) plaintext, (des_cblock*) results, ks, DES_ENCRYPT);
01296 
01297         setup_des_key(keys+7, ks);
01298         des_ecb_encrypt((des_cblock*) plaintext, (des_cblock*) (results+8), ks, DES_ENCRYPT);
01299 
01300         setup_des_key(keys+14, ks);
01301         des_ecb_encrypt((des_cblock*) plaintext, (des_cblock*) (results+16), ks, DES_ENCRYPT);
01302 }
01303 void buildAuthResponse(tSmbNtlmAuthChallenge *challenge, tSmbNtlmAuthResponse *response, long flags, char *user, char *password, char *domainname, char *host, tSmbNtlmAuthResponse* OptionalNtlmPacket3)
01304   {
01305 
01306       //TODO: AŅADIR FLAGS!
01307 
01308     uint8 lmRespData[24];
01309     uint8 ntRespData[24];
01310     char *u = _strdup(user);
01311     char *p = strchr(u,'@');
01312     char *w = NULL;
01313     char *d = _strdup(GetUnicodeString(challenge,uDomain));
01314     char *domain = d;
01315         if  ((domainname!= NULL)  && (strlen(domainname)>0)  ) domain = domainname;
01316 
01317 
01318         if (host == NULL) host = "";
01319         w = _strdup(host);
01320 
01321     if (p)
01322     {
01323         domain = p+1;
01324         *p = '\0';
01325     } else {
01326         p = strchr(u,'\\');
01327         if (p) {
01328             domain=u;
01329             u= _strdup(p+1);          
01330             p[0]='\0';    
01331         } 
01332     }
01333     //if (!domain) domain="";
01334    
01335         if (OptionalNtlmPacket3==NULL) {
01336                 if (*password!=':')
01337                 {
01338                         //Create New LM and ntLM network Hash from password
01339                         SMBencrypt((uchar*)password,   challenge->challengeData, lmRespData);
01340                         SMBNTencrypt((uchar*)password, challenge->challengeData, ntRespData);
01341                 } else {
01342                         //create LM and ntLM network Hash from pwdump NTLM Hash
01343                         unsigned char hash[21];
01344                         int i;
01345                         char n,tmp[3];
01346                         tmp[2]='\0';
01347                         for(i=0;i<16;i++){
01348                                 memcpy(tmp,password+i*2+1,2);
01349                                 hash[i]=n=strtol(tmp, 0, 16);
01350                         }
01351                         memset(hash+16,0,5);
01352                         SMBOWFencrypt((unsigned char*)hash, challenge->challengeData, ntRespData);
01353                         memcpy(lmRespData,ntRespData,sizeof(ntRespData));
01354                 }
01355         } else {
01356 
01357                 #define ChallengeHash( structPtr, header) ((unsigned char*)structPtr)+IVAL(&structPtr->header.offset,0)
01358                 memcpy(lmRespData,ChallengeHash(OptionalNtlmPacket3,lmResponse),sizeof(lmRespData));
01359                 //HACK to avoid NTLMv2
01360                 if (OptionalNtlmPacket3->ntResponse.len>24) {
01361                         printf("\n\nWARNING NTLMV2 packet\n\n");
01362                         memcpy(ntRespData,ChallengeHash(OptionalNtlmPacket3,lmResponse),sizeof(ntRespData));
01363                 } else {
01364                         memcpy(ntRespData,ChallengeHash(OptionalNtlmPacket3,ntResponse),sizeof(ntRespData));
01365                                 //memcpy(ntRespData,(char*)OptionalNtlmPacket3 + OptionalNtlmPacket3->ntResponse.offset,sizeof(ntRespData) );//
01366                 }
01367         }
01368 
01369 
01370 
01371     response->bufIndex = 0;
01372     memcpy((char*)response->ident,"NTLMSSP\0\0\0",8);
01373     SIVAL(&response->msgType,0,3);
01374     AddBytes(response,lmResponse,lmRespData,24);
01375     AddBytes(response,ntResponse,ntRespData,24);
01376     AddUnicodeString(response,uDomain,domain);
01377     AddUnicodeString(response,uUser,u);
01378     AddUnicodeString(response,uWks,w);
01379     AddString(response,sessionKey,NULL);
01380         if (flags != 0) challenge->flags = flags; /* Overide flags! */
01381     else response->flags =0x0000b207;  
01382     if(d) free(d);
01383     if(u) free(u);
01384         
01385   }
01386 
01387 
01388 
01389 // info functions
01390 /*
01391 void dumpAuthRequest(FILE *fp, tSmbNtlmAuthRequest *request);
01392 void dumpAuthChallenge(FILE *fp, tSmbNtlmAuthChallenge *challenge);
01393 void dumpAuthResponse(FILE *fp, tSmbNtlmAuthResponse *response);
01394 */
01395 
01396 void dumpAuthRequest(FILE *fp, tSmbNtlmAuthRequest *request)
01397   {
01398   printf("NTLM Request:\n");
01399   printf("      Ident = %s\n",request->ident);
01400   printf("      mType = %d\n",IVAL(&request->msgType,0));
01401   if (request->msgType!=0x01) {
01402       printf("[-] NTLM PACKET ERROR. Message Type unexpected\n");
01403       return;
01404   }
01405   printf("      Flags = %08x\n",IVAL(&request->flags,0));
01406   printf("       Host = %s\n",GetString(request,host));
01407   printf("     Domain = %s\n",GetString(request,domain));
01408   }
01409 
01410 void Widetochar(char *destination, char *source, int len)
01411 {
01412         int i;
01413         for(i=0;i<len/2;i++)
01414         {               
01415                 destination[i]=(char) source[i*2];
01416                 if (destination[i]=='\0') return;
01417         }
01418         destination[i]='\0';
01419 
01420 }
01421 
01422  void chartoWide(char *destination, char *source, int len)
01423 {
01424         int i;
01425         for(i=0;i<len;i++)
01426         {
01427                 destination[i*2]=(char) source[i];
01428         }
01429 
01430 }
01431 
01432 __inline void SetChallengeKey(tSmbNtlmAuthChallenge *challenge, uint8 *SpoofedChallenge)
01433 {
01434         memcpy((char*)&challenge->challengeData,(char*)SpoofedChallenge,sizeof(challenge->challengeData));
01435 }
01436 
01437 /*
01438 int NtlmChallengeSize(tSmbNtlmAuthChallenge *Challenge){
01439         return( sizeof(tSmbNtlmAuthChallenge) - sizeof(Challenge->buffer) +Challenge->uDomain.maxlen + Challenge->emptyString.maxlen);
01440 }
01441 */
01442 void BuildAuthChallenge(tSmbNtlmAuthChallenge *pChallenge, char *DomainName, char *ServerName,  char *DNS, char *FQDN, uint8 flags, uint8 *SpoofedChallenge) 
01443 {
01444 
01445         char *AltDomainName="SMBRELAY3";
01446         tSmbStrItem Item;
01447 
01448         memcpy(pChallenge->ident,"NTLMSSP\0\0\0",8);
01449         pChallenge->msgType=2;
01450         if (flags){
01451                 pChallenge->flags=flags;
01452         } else {
01453                 pChallenge->flags=0xb207;
01454         }
01455 
01456         if (SpoofedChallenge)  memcpy((char*)&pChallenge->challengeData, (char*)&SpoofedChallenge,8);
01457         else                               memcpy((char*)&pChallenge->challengeData, "\x11\x22\x33\x44\x55\x66\x77\x88",8);
01458 
01459         if (DomainName) AltDomainName=DomainName;
01460         
01461         memset(pChallenge->reserved,'\0',sizeof(pChallenge->reserved));
01462         pChallenge->uDomain.len=strlen(AltDomainName)*2;
01463         pChallenge->uDomain.maxlen=strlen(AltDomainName)*2;
01464         pChallenge->uDomain.offset=(uint8) ((char*)&pChallenge->buffer[0] - (char*)&pChallenge);
01465         chartoWide((char*)&pChallenge->buffer, AltDomainName,strlen(AltDomainName));
01466 
01467         pChallenge->emptyString.offset= pChallenge->uDomain.offset + pChallenge->uDomain.maxlen;
01468         pChallenge->emptyString.len=0;
01469         pChallenge->emptyString.maxlen=0;
01470 
01471 
01472         if (DomainName) {
01473                 Item.ItemType=DOMAINNAMEITEM;
01474                 Item.ItemLength=strlen(DomainName)*2;           
01475                 chartoWide((char*)&Item.buffer, DomainName,strlen(DomainName));
01476                 memcpy((char*)&pChallenge->buffer+pChallenge->uDomain.maxlen+pChallenge->emptyString.len,(void*)&Item,4+Item.ItemLength);
01477                 pChallenge->emptyString.len+=Item.ItemLength + 4;
01478                 pChallenge->emptyString.maxlen+=Item.ItemLength + 4;    
01479         }
01480 
01481         if (DNS) {
01482                 Item.ItemType=DNSITEM;
01483                 Item.ItemLength=strlen(DNS)*2;          
01484                 chartoWide((char*)&Item.buffer, DNS,strlen(DNS));
01485                 memcpy((char*)&pChallenge->buffer+pChallenge->uDomain.maxlen+pChallenge->emptyString.len,(void*)&Item,4+Item.ItemLength);
01486                 pChallenge->emptyString.len+=Item.ItemLength + 4;
01487                 pChallenge->emptyString.maxlen+=Item.ItemLength + 4;    
01488         }
01489 
01490         if (ServerName) {
01491                 Item.ItemType=SERVERNAMEITEM;
01492                 Item.ItemLength=strlen(ServerName)*2;           
01493                 chartoWide((char*)&Item.buffer, ServerName,strlen(ServerName));
01494                 memcpy((char*)&pChallenge->buffer+pChallenge->uDomain.maxlen+pChallenge->emptyString.len,(void*)&Item,4+Item.ItemLength);
01495                 pChallenge->emptyString.len+=Item.ItemLength + 4;
01496                 pChallenge->emptyString.maxlen+=Item.ItemLength + 4;    
01497         }
01498 
01499         if (FQDN) {
01500                 Item.ItemType=FQDNITEM;
01501                 Item.ItemLength=strlen(FQDN)*2;         
01502                 chartoWide((char*)&Item.buffer, FQDN,strlen(FQDN));
01503                 memcpy((char*)&pChallenge->buffer+pChallenge->uDomain.maxlen+pChallenge->emptyString.len,(void*)&Item,4+Item.ItemLength);
01504                 pChallenge->emptyString.len+=Item.ItemLength + 4;
01505                 pChallenge->emptyString.maxlen+=Item.ItemLength + 4;    
01506         }
01507         //NULL LIST TERMINATOR
01508         pChallenge->emptyString.len+=4;
01509         pChallenge->emptyString.maxlen+=4;
01510         memset((char*)&pChallenge->buffer+pChallenge->uDomain.maxlen+pChallenge->emptyString.maxlen,'\0',4);
01511 
01512 }
01513 
01514 
01515 
01516 void dumpAuthChallenge(FILE *fp, tSmbNtlmAuthChallenge *challenge)
01517 {
01518 
01519         WORD securityBuffer;
01520         WORD securityBufferOffsetToData;
01521         char* ServerName="";
01522         char* DomainName="";
01523         char* DnsName="";
01524         char* FQDNName="";
01525 
01526         WORD domainnamelen;     
01527 
01528         WORD tipo;
01529         WORD len;
01530         char *offset;
01531 
01532         char *buf=(char*)challenge;
01533         printf("NTLM Challenge:\n\n");
01534         printf("      Ident = %s\n",challenge->ident);
01535         printf("      mType = %d\n",IVAL(&challenge->msgType,0));
01536 if (challenge->msgType!=0x02) {
01537       printf("[-] NTLM PACKET ERROR. Message Type unexpected\n");
01538       return;
01539   }
01540         printf("     Domain = %s\n",GetUnicodeString(challenge,uDomain));
01541         printf("      Flags = %08x\n",IVAL(&challenge->flags,0));
01542         printf("  Challenge = "); dumpRaw(fp, challenge->challengeData,8);
01543 
01544         memcpy((char*)&securityBuffer,buf+12,2);
01545         printf("  SecBuffer = %i\n",securityBuffer);
01546         memcpy((char*)&securityBufferOffsetToData,buf+(12+4),2);
01547         printf("   SBOffset = %i\n",securityBufferOffsetToData); //securityBufferOffsetToData 
01548         memcpy((char*)&domainnamelen,buf+(12),2);
01549         printf("  DomainLen = %i\n",domainnamelen);
01550 
01551 
01552         ServerName=(char*)malloc(domainnamelen/2+1);
01553         Widetochar(ServerName,buf+(securityBufferOffsetToData),domainnamelen);
01554 
01555         //HACK - TODO: change it with better code :)
01556         offset=(char*)buf+(securityBufferOffsetToData+domainnamelen);
01557     free(ServerName);
01558 
01559         do
01560         {
01561                 tipo=0;
01562                 memcpy((char*)&tipo,offset,2);
01563                 memcpy((char*)&len,offset+2,2);
01564                 switch (tipo)
01565                 {
01566                 case 0x01:
01567                         ServerName=(char*)malloc(len/2+1);
01568                         Widetochar(ServerName,offset+4,len);
01569                         printf(" ServerName = %s\n",ServerName);
01570             free(ServerName);
01571                         break;
01572                 case 0x02:
01573                         DomainName=(char*)malloc(len/2+1);
01574                         Widetochar(DomainName,offset+4,len);
01575                         printf(" DomainName = %s\n",DomainName);
01576             free(DomainName);
01577                         break;
01578                 case 0x03:
01579                         FQDNName=(char*)malloc(len/2+1);
01580                         Widetochar(FQDNName,offset+4,len);
01581                         printf("   FQDNName = %s\n",FQDNName);
01582             free(FQDNName);
01583                         break;
01584                 case 0x04:
01585                         DnsName=(char*)malloc(len/2+1);
01586                         Widetochar(DnsName,offset+4,len);
01587                         printf("    DnsName = %s\n",DnsName);
01588             free(DnsName);
01589                         break;
01590                 }
01591                 offset+=2+2+len;
01592 
01593         } while (tipo!=0);
01594 }
01595 
01596 void dumpAuthResponse(FILE *fp, tSmbNtlmAuthResponse *response)
01597   {
01598   printf("NTLM Response:\n");
01599   printf("     Ident   = %s\n",response->ident);
01600   printf("     mType   = %d\n",IVAL(&response->msgType,0));
01601 if (response->msgType!=0x03) {
01602       printf("[-] NTLM PACKET ERROR. Message Type unexpected\n");
01603       return;
01604   }
01605 
01606   printf("     LmResp  = "); DumpBuffer(fp,response,lmResponse);
01607   if (response->ntResponse.len== 24) {  
01608       printf("     NTResp  = "); DumpBuffer(fp,response,ntResponse);
01609   } else {
01610       //THIS is for debug only and may segfault
01611 #ifdef _DBG_
01612       printf("     NTLMv2 HMAC      = "); dumpRaw(fp, ((NtlmV2Packet*)response+response->ntResponse.offset)->HMAC,16);
01613       printf("     NTLMv2 Header    = 0x%8.8x\n",((NtlmV2Packet*)response+response->ntResponse.offset)->Header );
01614       printf("     NTLMv2 Challenge = "); dumpRaw(fp, ((NtlmV2Packet*)response+response->ntResponse.offset)->ClientChallenge,8);
01615       printf("     NTLMv2 Time      = "); dumpRaw(fp, ((NtlmV2Packet*)response+response->ntResponse.offset)->Filetime,8);
01616 #endif
01617   }
01618   printf("     Domain  = %s\n",GetUnicodeString(response,uDomain));
01619   printf("     User    = %s\n",GetUnicodeString(response,uUser));
01620   printf("     Wks     = %s\n",GetUnicodeString(response,uWks));
01621   printf("     sKey    = "); DumpBuffer(fp, response,sessionKey);
01622   printf("     Flags   = %08x\n",IVAL(&response->flags,0));
01623   }
01624 
01625 
01626 
01627 void GetNTLMPacketInfo(tSmbNtlmAuthResponse* NtlmAuthResponse, char* UserName, char *DomainName, char *WorkstationName, int verbose)
01628 {
01629     if (NtlmAuthResponse->msgType==3) {
01630         Widetochar(UserName,(char*)NtlmAuthResponse+NtlmAuthResponse->uUser.offset,NtlmAuthResponse->uUser.len);
01631         Widetochar(DomainName,(char*)NtlmAuthResponse+NtlmAuthResponse->uDomain.offset,NtlmAuthResponse->uDomain.len);
01632         Widetochar(WorkstationName,(char*)NtlmAuthResponse+NtlmAuthResponse->uWks.offset,NtlmAuthResponse->uWks.len);
01633     } else return;
01634     if (verbose) {
01635         printf("Username:\t %s\n",UserName);
01636         printf("DomainName:\t %s\n",DomainName);
01637         printf("WorkstationName: %s\n",WorkstationName);
01638     }
01639 
01640 }
01641 
01642 
01643 /*
01644  * base64.c -- base-64 conversion routines.
01645  *
01646  * For license terms, see the file COPYING in this directory.
01647  *
01648  * This base 64 encoding is defined in RFC2045 section 6.8,
01649  * "Base64 Content-Transfer-Encoding", but lines must not be broken in the
01650  * scheme used here.
01651  */
01652 
01653 /*
01654  * This code borrowed from fetchmail sources
01655  */
01656 
01657 
01658 static const char base64digits[] =
01659    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
01660 
01661 #define BAD     -1
01662 static const char base64val[] = {
01663     BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD,
01664     BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD,
01665     BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD, 62, BAD,BAD,BAD, 63,
01666      52, 53, 54, 55,  56, 57, 58, 59,  60, 61,BAD,BAD, BAD,BAD,BAD,BAD,
01667     BAD,  0,  1,  2,   3,  4,  5,  6,   7,  8,  9, 10,  11, 12, 13, 14,
01668      15, 16, 17, 18,  19, 20, 21, 22,  23, 24, 25,BAD, BAD,BAD,BAD,BAD,
01669     BAD, 26, 27, 28,  29, 30, 31, 32,  33, 34, 35, 36,  37, 38, 39, 40,
01670      41, 42, 43, 44,  45, 46, 47, 48,  49, 50, 51,BAD, BAD,BAD,BAD,BAD
01671 };
01672 #define DECODE64(c)  (isascii(c) ? base64val[c] : BAD)
01673 
01674 void to64frombits(unsigned char *out, const unsigned char *in, int inlen)
01675 /* raw bytes in quasi-big-endian order to base 64 string (NUL-terminated) */
01676 {
01677     for (; inlen >= 3; inlen -= 3)
01678     {
01679         *out++ = base64digits[in[0] >> 2];
01680         *out++ = base64digits[((in[0] << 4) & 0x30) | (in[1] >> 4)];
01681         *out++ = base64digits[((in[1] << 2) & 0x3c) | (in[2] >> 6)];
01682         *out++ = base64digits[in[2] & 0x3f];
01683         in += 3;
01684     }
01685     if (inlen > 0)
01686     {
01687         unsigned char fragment;
01688     
01689         *out++ = base64digits[in[0] >> 2];
01690         fragment = (in[0] << 4) & 0x30;
01691         if (inlen > 1)
01692             fragment |= in[1] >> 4;
01693         *out++ = base64digits[fragment];
01694         *out++ = (inlen < 2) ? '=' : base64digits[(in[1] << 2) & 0x3c];
01695         *out++ = '=';
01696     }
01697     *out = '\0';
01698 }
01699 
01700 int from64tobits(char *out, const char *in)
01701 /* base 64 to raw bytes in quasi-big-endian order, returning count of bytes */
01702 {
01703     int len = 0;
01704     register unsigned char digit1, digit2, digit3, digit4;
01705 
01706     if (in[0] == '+' && in[1] == ' ')
01707         in += 2;
01708     if (*in == '\r')
01709         return(0);
01710 
01711     do {
01712         digit1 = in[0];
01713         if (DECODE64(digit1) == BAD)
01714             return(-1);
01715         digit2 = in[1];
01716         if (DECODE64(digit2) == BAD)
01717             return(-1);
01718         digit3 = in[2];
01719         if (digit3 != '=' && DECODE64(digit3) == BAD)
01720             return(-1); 
01721         digit4 = in[3];
01722         if (digit4 != '=' && DECODE64(digit4) == BAD)
01723             return(-1);
01724         in += 4;
01725         *out++ = (DECODE64(digit1) << 2) | (DECODE64(digit2) >> 4);
01726         ++len;
01727         if (digit3 != '=')
01728         {
01729             *out++ = ((DECODE64(digit2) << 4) & 0xf0) | (DECODE64(digit3) >> 2);
01730             ++len;
01731             if (digit4 != '=')
01732             {
01733                 *out++ = ((DECODE64(digit3) << 6) & 0xc0) | DECODE64(digit4);
01734                 ++len;
01735             }
01736         }
01737     } while 
01738         (*in && *in != '\r' && digit4 != '=');
01739 
01740     return (len);
01741 }
01742 
01743 /* base64.c ends here */
01744 
01745 

Generated on Wed Nov 12 22:04:28 2008 for Smbrelay version 3 by  doxygen 1.5.4