Logo Search packages:      
Sourcecode: pan version File versions  Download package

auth-spa.c

/* 
 * All the code used here was torn by Marc Prud'hommeaux out of the 
 * Samba project (by Andrew Tridgell, Jeremy Allison, and others).
 */
#define DEBUG(a,b) ;

extern int DEBUGLEVEL;

#include "auth-spa.h"
#include <assert.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#ifndef _AIX
typedef unsigned char uchar;
#endif


typedef int BOOL;
#define False 0
#define True  1

/* base64.c */
int from64tobits(char *, const char *);

#define ntlm_request_length(ptr) (((ptr)->buffer - (uint8*)(ptr)) + (ptr)->bufIndex)


/* public: */



#ifndef _BYTEORDER_H
#define _BYTEORDER_H

/*
   This file implements macros for machine independent short and 
   int manipulation

Here is a description of this file that I emailed to the samba list once:

> I am confused about the way that byteorder.h works in Samba. I have
> looked at it, and I would have thought that you might make a distinction
> between LE and BE machines, but you only seem to distinguish between 386
> and all other architectures.
> 
> Can you give me a clue?

sure.

The distinction between 386 and other architectures is only there as
an optimisation. You can take it out completely and it will make no
difference. The routines (macros) in byteorder.h are totally byteorder
independent. The 386 optimsation just takes advantage of the fact that
the x86 processors don't care about alignment, so we don't have to
align ints on int boundaries etc. If there are other processors out
there that aren't alignment sensitive then you could also define
CAREFUL_ALIGNMENT=0 on those processors as well.

Ok, now to the macros themselves. I'll take a simple example, say we
want to extract a 2 byte integer from a SMB packet and put it into a
type called uint16 that is in the local machines byte order, and you
want to do it with only the assumption that uint16 is _at_least_ 16
bits long (this last condition is very important for architectures
that don't have any int types that are 2 bytes long)

You do this:

#define CVAL(buf,pos) (((unsigned char *)(buf))[pos])
#define PVAL(buf,pos) ((unsigned)CVAL(buf,pos))
#define SVAL(buf,pos) (PVAL(buf,pos)|PVAL(buf,(pos)+1)<<8)

then to extract a uint16 value at offset 25 in a buffer you do this:

char *buffer = foo_bar();
uint16 xx = SVAL(buffer,25);

We are using the byteoder independence of the ANSI C bitshifts to do
the work. A good optimising compiler should turn this into efficient
code, especially if it happens to have the right byteorder :-)

I know these macros can be made a bit tidier by removing some of the
casts, but you need to look at byteorder.h as a whole to see the
reasoning behind them. byteorder.h defines the following macros:

SVAL(buf,pos) - extract a 2 byte SMB value
IVAL(buf,pos) - extract a 4 byte SMB value
SVALS(buf,pos) signed version of SVAL()
IVALS(buf,pos) signed version of IVAL()

SSVAL(buf,pos,val) - put a 2 byte SMB value into a buffer
SIVAL(buf,pos,val) - put a 4 byte SMB value into a buffer
SSVALS(buf,pos,val) - signed version of SSVAL()
SIVALS(buf,pos,val) - signed version of SIVAL()

RSVAL(buf,pos) - like SVAL() but for NMB byte ordering
RSVALS(buf,pos) - like SVALS() but for NMB byte ordering
RIVAL(buf,pos) - like IVAL() but for NMB byte ordering
RIVALS(buf,pos) - like IVALS() but for NMB byte ordering
RSSVAL(buf,pos,val) - like SSVAL() but for NMB ordering
RSIVAL(buf,pos,val) - like SIVAL() but for NMB ordering
RSIVALS(buf,pos,val) - like SIVALS() but for NMB ordering

it also defines lots of intermediate macros, just ignore those :-)

*/

/* some switch macros that do both store and read to and from SMB buffers */

#define RW_PCVAL(read,inbuf,outbuf,len) \
      { if (read) { PCVAL (inbuf,0,outbuf,len); } \
      else      { PSCVAL(inbuf,0,outbuf,len); } }

#define RW_PIVAL(read,big_endian,inbuf,outbuf,len) \
      { if (read) { if (big_endian) { RPIVAL(inbuf,0,outbuf,len); } else { PIVAL(inbuf,0,outbuf,len); } } \
      else      { if (big_endian) { RPSIVAL(inbuf,0,outbuf,len); } else { PSIVAL(inbuf,0,outbuf,len); } } }

#define RW_PSVAL(read,big_endian,inbuf,outbuf,len) \
      { if (read) { if (big_endian) { RPSVAL(inbuf,0,outbuf,len); } else { PSVAL(inbuf,0,outbuf,len); } } \
      else      { if (big_endian) { RPSSVAL(inbuf,0,outbuf,len); } else { PSSVAL(inbuf,0,outbuf,len); } } }

#define RW_CVAL(read, inbuf, outbuf, offset) \
      { if (read) { (outbuf) = CVAL (inbuf,offset); } \
      else      { SCVAL(inbuf,offset,outbuf); } }

#define RW_IVAL(read, big_endian, inbuf, outbuf, offset) \
      { if (read) { (outbuf) = ((big_endian) ? RIVAL(inbuf,offset) : IVAL (inbuf,offset)); } \
      else      { if (big_endian) { RSIVAL(inbuf,offset,outbuf); } else { SIVAL(inbuf,offset,outbuf); } } }

#define RW_SVAL(read, big_endian, inbuf, outbuf, offset) \
      { if (read) { (outbuf) = ((big_endian) ? RSVAL(inbuf,offset) : SVAL (inbuf,offset)); } \
      else      { if (big_endian) { RSSVAL(inbuf,offset,outbuf); } else { SSVAL(inbuf,offset,outbuf); } } }

#undef CAREFUL_ALIGNMENT

/* we know that the 386 can handle misalignment and has the "right" 
   byteorder */
#ifdef __i386__
#define CAREFUL_ALIGNMENT 0
#endif

#ifndef CAREFUL_ALIGNMENT
#define CAREFUL_ALIGNMENT 1
#endif

#define CVAL(buf,pos) (((unsigned char *)(buf))[pos])
#define PVAL(buf,pos) ((unsigned)CVAL(buf,pos))
#define SCVAL(buf,pos,val) (CVAL(buf,pos) = (val))


#if CAREFUL_ALIGNMENT

#define SVAL(buf,pos) (PVAL(buf,pos)|PVAL(buf,(pos)+1)<<8)
#define IVAL(buf,pos) (SVAL(buf,pos)|SVAL(buf,(pos)+2)<<16)
#define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8)
#define SIVALX(buf,pos,val) (SSVALX(buf,pos,val&0xFFFF),SSVALX(buf,pos+2,val>>16))
#define SVALS(buf,pos) ((int16)SVAL(buf,pos))
#define IVALS(buf,pos) ((int32)IVAL(buf,pos))
#define SSVAL(buf,pos,val) SSVALX((buf),(pos),((uint16)(val)))
#define SIVAL(buf,pos,val) SIVALX((buf),(pos),((uint32)(val)))
#define SSVALS(buf,pos,val) SSVALX((buf),(pos),((int16)(val)))
#define SIVALS(buf,pos,val) SIVALX((buf),(pos),((int32)(val)))

#else /* CAREFUL_ALIGNMENT */

/* this handles things for architectures like the 386 that can handle
   alignment errors */
/*
   WARNING: This section is dependent on the length of int16 and int32
   being correct 
*/

/* get single value from an SMB buffer */
#define SVAL(buf,pos) (*(uint16 *)((char *)(buf) + (pos)))
#define IVAL(buf,pos) (*(uint32 *)((char *)(buf) + (pos)))
#define SVALS(buf,pos) (*(int16 *)((char *)(buf) + (pos)))
#define IVALS(buf,pos) (*(int32 *)((char *)(buf) + (pos)))

/* store single value in an SMB buffer */
#define SSVAL(buf,pos,val) SVAL(buf,pos)=((uint16)(val))
#define SIVAL(buf,pos,val) IVAL(buf,pos)=((uint32)(val))
#define SSVALS(buf,pos,val) SVALS(buf,pos)=((int16)(val))
#define SIVALS(buf,pos,val) IVALS(buf,pos)=((int32)(val))

#endif /* CAREFUL_ALIGNMENT */

/* macros for reading / writing arrays */

#define SMBMACRO(macro,buf,pos,val,len,size) \
{ int l; for (l = 0; l < (len); l++) (val)[l] = macro((buf), (pos) + (size)*l); }

#define SSMBMACRO(macro,buf,pos,val,len,size) \
{ int l; for (l = 0; l < (len); l++) macro((buf), (pos) + (size)*l, (val)[l]); }

/* reads multiple data from an SMB buffer */
#define PCVAL(buf,pos,val,len) SMBMACRO(CVAL,buf,pos,val,len,1)
#define PSVAL(buf,pos,val,len) SMBMACRO(SVAL,buf,pos,val,len,2)
#define PIVAL(buf,pos,val,len) SMBMACRO(IVAL,buf,pos,val,len,4)
#define PCVALS(buf,pos,val,len) SMBMACRO(CVALS,buf,pos,val,len,1)
#define PSVALS(buf,pos,val,len) SMBMACRO(SVALS,buf,pos,val,len,2)
#define PIVALS(buf,pos,val,len) SMBMACRO(IVALS,buf,pos,val,len,4)

/* stores multiple data in an SMB buffer */
#define PSCVAL(buf,pos,val,len) SSMBMACRO(SCVAL,buf,pos,val,len,1)
#define PSSVAL(buf,pos,val,len) SSMBMACRO(SSVAL,buf,pos,val,len,2)
#define PSIVAL(buf,pos,val,len) SSMBMACRO(SIVAL,buf,pos,val,len,4)
#define PSCVALS(buf,pos,val,len) SSMBMACRO(SCVALS,buf,pos,val,len,1)
#define PSSVALS(buf,pos,val,len) SSMBMACRO(SSVALS,buf,pos,val,len,2)
#define PSIVALS(buf,pos,val,len) SSMBMACRO(SIVALS,buf,pos,val,len,4)


/* now the reverse routines - these are used in nmb packets (mostly) */
#define SREV(x) ((((x)&0xFF)<<8) | (((x)>>8)&0xFF))
#define IREV(x) ((SREV(x)<<16) | (SREV((x)>>16)))

#define RSVAL(buf,pos) SREV(SVAL(buf,pos))
#define RSVALS(buf,pos) SREV(SVALS(buf,pos))
#define RIVAL(buf,pos) IREV(IVAL(buf,pos))
#define RIVALS(buf,pos) IREV(IVALS(buf,pos))
#define RSSVAL(buf,pos,val) SSVAL(buf,pos,SREV(val))
#define RSSVALS(buf,pos,val) SSVALS(buf,pos,SREV(val))
#define RSIVAL(buf,pos,val) SIVAL(buf,pos,IREV(val))
#define RSIVALS(buf,pos,val) SIVALS(buf,pos,IREV(val))

/* reads multiple data from an SMB buffer (big-endian) */
#define RPSVAL(buf,pos,val,len) SMBMACRO(RSVAL,buf,pos,val,len,2)
#define RPIVAL(buf,pos,val,len) SMBMACRO(RIVAL,buf,pos,val,len,4)
#define RPSVALS(buf,pos,val,len) SMBMACRO(RSVALS,buf,pos,val,len,2)
#define RPIVALS(buf,pos,val,len) SMBMACRO(RIVALS,buf,pos,val,len,4)

/* stores multiple data in an SMB buffer (big-endian) */
#define RPSSVAL(buf,pos,val,len) SSMBMACRO(RSSVAL,buf,pos,val,len,2)
#define RPSIVAL(buf,pos,val,len) SSMBMACRO(RSIVAL,buf,pos,val,len,4)
#define RPSSVALS(buf,pos,val,len) SSMBMACRO(RSSVALS,buf,pos,val,len,2)
#define RPSIVALS(buf,pos,val,len) SSMBMACRO(RSIVALS,buf,pos,val,len,4)

#define DBG_RW_PCVAL(charmode,string,depth,base,read,inbuf,outbuf,len) \
      { RW_PCVAL(read,inbuf,outbuf,len) \
      DEBUG(5,("%s%04x %s: ", \
             tab_depth(depth), base,string)); \
    if (charmode) print_asc(5, (unsigned char*)(outbuf), (len)); else \
      { int idx; for (idx = 0; idx < len; idx++) { DEBUG(5,("%02x ", (outbuf)[idx])); } } \
      DEBUG(5,("\n")); } 

#define DBG_RW_PSVAL(charmode,string,depth,base,read,big_endian,inbuf,outbuf,len) \
      { RW_PSVAL(read,big_endian,inbuf,outbuf,len) \
      DEBUG(5,("%s%04x %s: ", \
             tab_depth(depth), base,string)); \
    if (charmode) print_asc(5, (unsigned char*)(outbuf), 2*(len)); else \
      { int idx; for (idx = 0; idx < len; idx++) { DEBUG(5,("%04x ", (outbuf)[idx])); } } \
      DEBUG(5,("\n")); }

#define DBG_RW_PIVAL(charmode,string,depth,base,read,big_endian,inbuf,outbuf,len) \
      { RW_PIVAL(read,big_endian,inbuf,outbuf,len) \
      DEBUG(5,("%s%04x %s: ", \
             tab_depth(depth), base,string)); \
    if (charmode) print_asc(5, (unsigned char*)(outbuf), 4*(len)); else \
      { int idx; for (idx = 0; idx < len; idx++) { DEBUG(5,("%08x ", (outbuf)[idx])); } } \
      DEBUG(5,("\n")); }

#define DBG_RW_CVAL(string,depth,base,read,inbuf,outbuf) \
      { RW_CVAL(read,inbuf,outbuf,0) \
      DEBUG(5,("%s%04x %s: %02x\n", \
             tab_depth(depth), base, string, outbuf)); }

#define DBG_RW_SVAL(string,depth,base,read,big_endian,inbuf,outbuf) \
      { RW_SVAL(read,big_endian,inbuf,outbuf,0) \
      DEBUG(5,("%s%04x %s: %04x\n", \
             tab_depth(depth), base, string, outbuf)); }

#define DBG_RW_IVAL(string,depth,base,read,big_endian,inbuf,outbuf) \
      { RW_IVAL(read,big_endian,inbuf,outbuf,0) \
      DEBUG(5,("%s%04x %s: %08x\n", \
             tab_depth(depth), base, string, outbuf)); }

#endif /* _BYTEORDER_H */

extern void E_P16(unsigned char *p14,unsigned char *p16);
extern void E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24);
extern void D_P16(unsigned char *p14, unsigned char *in, unsigned char *out);
extern void E_old_pw_hash( unsigned char *p14, unsigned char *in, unsigned char *out);
extern void cred_hash1(unsigned char *out,unsigned char *in,unsigned char *key);
extern void cred_hash2(unsigned char *out,unsigned char *in,unsigned char *key);
extern void cred_hash3(unsigned char *out,unsigned char *in,unsigned char *key, int forw);
extern void SamOEMhash( unsigned char *data, unsigned char *key, int val);

void SMBencrypt(const uchar *passwd, uchar *c8, uchar *p24);
void SMBNTencrypt(const uchar *passwd, uchar *c8, uchar *p24);
extern void mdfour(unsigned char *out, const unsigned char *in, int n);


/*
 * base64.c -- base-64 conversion routines.
 *
 * For license terms, see the file COPYING in this directory.
 *
 * This base 64 encoding is defined in RFC2045 section 6.8,
 * "Base64 Content-Transfer-Encoding", but lines must not be broken in the
 * scheme used here.
 */

static const char base64digits[] =
   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

#define BAD -1
static const char base64val[] = {
    BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD,
    BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD,
    BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD, 62, BAD,BAD,BAD, 63,
     52, 53, 54, 55,  56, 57, 58, 59,  60, 61,BAD,BAD, BAD,BAD,BAD,BAD,
    BAD,  0,  1,  2,   3,  4,  5,  6,   7,  8,  9, 10,  11, 12, 13, 14,
     15, 16, 17, 18,  19, 20, 21, 22,  23, 24, 25,BAD, BAD,BAD,BAD,BAD,
    BAD, 26, 27, 28,  29, 30, 31, 32,  33, 34, 35, 36,  37, 38, 39, 40,
     41, 42, 43, 44,  45, 46, 47, 48,  49, 50, 51,BAD, BAD,BAD,BAD,BAD
};
#define DECODE64(c)  (isascii(c) ? base64val[c] : BAD)

void spa_bits_to_base64(unsigned char *out, const unsigned char *in, int inlen)
/* raw bytes in quasi-big-endian order to base 64 string (NUL-terminated) */
{
    for (; inlen >= 3; inlen -= 3)
    {
      *out++ = base64digits[in[0] >> 2];
      *out++ = base64digits[((in[0] << 4) & 0x30) | (in[1] >> 4)];
      *out++ = base64digits[((in[1] << 2) & 0x3c) | (in[2] >> 6)];
      *out++ = base64digits[in[2] & 0x3f];
      in += 3;
    }
    if (inlen > 0)
    {
      unsigned char fragment;
    
      *out++ = base64digits[in[0] >> 2];
      fragment = (in[0] << 4) & 0x30;
      if (inlen > 1)
          fragment |= in[1] >> 4;
      *out++ = base64digits[fragment];
      *out++ = (inlen < 2) ? '=' : base64digits[(in[1] << 2) & 0x3c];
      *out++ = '=';
    }
    *out = '\0';
}

int spa_base64_to_bits (char *out, const char *in)
/* base 64 to raw bytes in quasi-big-endian order, returning count of bytes */
{
    int len = 0;
    register unsigned char digit1, digit2, digit3, digit4;

    if (in[0] == '+' && in[1] == ' ')
      in += 2;
    if (*in == '\r')
      return(0);

    do {
      digit1 = in[0];
      if (DECODE64(digit1) == BAD)
          return(-1);
      digit2 = in[1];
      if (DECODE64(digit2) == BAD)
          return(-1);
      digit3 = in[2];
      if (digit3 != '=' && DECODE64(digit3) == BAD)
          return(-1); 
      digit4 = in[3];
      if (digit4 != '=' && DECODE64(digit4) == BAD)
          return(-1);
      in += 4;
      *out++ = (DECODE64(digit1) << 2) | (DECODE64(digit2) >> 4);
      ++len;
      if (digit3 != '=')
      {
          *out++ = ((DECODE64(digit2) << 4) & 0xf0) | (DECODE64(digit3) >> 2);
          ++len;
          if (digit4 != '=')
          {
            *out++ = ((DECODE64(digit3) << 6) & 0xc0) | DECODE64(digit4);
            ++len;
          }
      }
    } while 
      (*in && *in != '\r' && digit4 != '=');

    return (len);
}

/* base64.c ends here */

/* 
   Unix SMB/Netbios implementation.
   Version 1.9.

   a partial implementation of DES designed for use in the 
   SMB authentication protocol

   Copyright (C) Andrew Tridgell 1998
   
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
   
   This program 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 General Public License for more details.
   
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/


/* NOTES: 

   This code makes no attempt to be fast! In fact, it is a very
   slow implementation 

   This code is NOT a complete DES implementation. It implements only
   the minimum necessary for SMB authentication, as used by all SMB
   products (including every copy of Microsoft Windows95 ever sold)

   In particular, it can only do a unchained forward DES pass. This
   means it is not possible to use this code for encryption/decryption
   of data, instead it is only useful as a "hash" algorithm.

   There is no entry point into this code that allows normal DES operation.

   I believe this means that this code does not come under ITAR
   regulations but this is NOT a legal opinion. If you are concerned
   about the applicability of ITAR regulations to this code then you
   should confirm it for yourself (and maybe let me know if you come
   up with a different answer to the one above)
*/


#define uchar unsigned char

static uchar perm1[56] = {57, 49, 41, 33, 25, 17,  9,
                   1, 58, 50, 42, 34, 26, 18,
                  10,  2, 59, 51, 43, 35, 27,
                  19, 11,  3, 60, 52, 44, 36,
                  63, 55, 47, 39, 31, 23, 15,
                   7, 62, 54, 46, 38, 30, 22,
                  14,  6, 61, 53, 45, 37, 29,
                  21, 13,  5, 28, 20, 12,  4};

static uchar perm2[48] = {14, 17, 11, 24,  1,  5,
                         3, 28, 15,  6, 21, 10,
                        23, 19, 12,  4, 26,  8,
                        16,  7, 27, 20, 13,  2,
                        41, 52, 31, 37, 47, 55,
                        30, 40, 51, 45, 33, 48,
                        44, 49, 39, 56, 34, 53,
                        46, 42, 50, 36, 29, 32};

static uchar perm3[64] = {58, 50, 42, 34, 26, 18, 10,  2,
                  60, 52, 44, 36, 28, 20, 12,  4,
                  62, 54, 46, 38, 30, 22, 14,  6,
                  64, 56, 48, 40, 32, 24, 16,  8,
                  57, 49, 41, 33, 25, 17,  9,  1,
                  59, 51, 43, 35, 27, 19, 11,  3,
                  61, 53, 45, 37, 29, 21, 13,  5,
                  63, 55, 47, 39, 31, 23, 15,  7};

static uchar perm4[48] = {   32,  1,  2,  3,  4,  5,
                            4,  5,  6,  7,  8,  9,
                            8,  9, 10, 11, 12, 13,
                           12, 13, 14, 15, 16, 17,
                           16, 17, 18, 19, 20, 21,
                           20, 21, 22, 23, 24, 25,
                           24, 25, 26, 27, 28, 29,
                           28, 29, 30, 31, 32,  1};

static uchar perm5[32] = {      16,  7, 20, 21,
                              29, 12, 28, 17,
                               1, 15, 23, 26,
                               5, 18, 31, 10,
                               2,  8, 24, 14,
                              32, 27,  3,  9,
                              19, 13, 30,  6,
                              22, 11,  4, 25};


static uchar perm6[64] ={ 40,  8, 48, 16, 56, 24, 64, 32,
                        39,  7, 47, 15, 55, 23, 63, 31,
                        38,  6, 46, 14, 54, 22, 62, 30,
                        37,  5, 45, 13, 53, 21, 61, 29,
                        36,  4, 44, 12, 52, 20, 60, 28,
                        35,  3, 43, 11, 51, 19, 59, 27,
                        34,  2, 42, 10, 50, 18, 58, 26,
                        33,  1, 41,  9, 49, 17, 57, 25};


static uchar sc[16] = {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};

static uchar sbox[8][4][16] = {
      {{14,  4, 13,  1,  2, 15, 11,  8,  3, 10,  6, 12,  5,  9,  0,  7},
       {0, 15,  7,  4, 14,  2, 13,  1, 10,  6, 12, 11,  9,  5,  3,  8},
       {4,  1, 14,  8, 13,  6,  2, 11, 15, 12,  9,  7,  3, 10,  5,  0},
       {15, 12,  8,  2,  4,  9,  1,  7,  5, 11,  3, 14, 10,  0,  6, 13}},

      {{15,  1,  8, 14,  6, 11,  3,  4,  9,  7,  2, 13, 12,  0,  5, 10},
       {3, 13,  4,  7, 15,  2,  8, 14, 12,  0,  1, 10,  6,  9, 11,  5},
       {0, 14,  7, 11, 10,  4, 13,  1,  5,  8, 12,  6,  9,  3,  2, 15},
       {13,  8, 10,  1,  3, 15,  4,  2, 11,  6,  7, 12,  0,  5, 14,  9}},

      {{10,  0,  9, 14,  6,  3, 15,  5,  1, 13, 12,  7, 11,  4,  2,  8},
       {13,  7,  0,  9,  3,  4,  6, 10,  2,  8,  5, 14, 12, 11, 15,  1},
       {13,  6,  4,  9,  8, 15,  3,  0, 11,  1,  2, 12,  5, 10, 14,  7},
       {1, 10, 13,  0,  6,  9,  8,  7,  4, 15, 14,  3, 11,  5,  2, 12}},

      {{7, 13, 14,  3,  0,  6,  9, 10,  1,  2,  8,  5, 11, 12,  4, 15},
       {13,  8, 11,  5,  6, 15,  0,  3,  4,  7,  2, 12,  1, 10, 14,  9},
       {10,  6,  9,  0, 12, 11,  7, 13, 15,  1,  3, 14,  5,  2,  8,  4},
       {3, 15,  0,  6, 10,  1, 13,  8,  9,  4,  5, 11, 12,  7,  2, 14}},

      {{2, 12,  4,  1,  7, 10, 11,  6,  8,  5,  3, 15, 13,  0, 14,  9},
       {14, 11,  2, 12,  4,  7, 13,  1,  5,  0, 15, 10,  3,  9,  8,  6},
       {4,  2,  1, 11, 10, 13,  7,  8, 15,  9, 12,  5,  6,  3,  0, 14},
       {11,  8, 12,  7,  1, 14,  2, 13,  6, 15,  0,  9, 10,  4,  5,  3}},

      {{12,  1, 10, 15,  9,  2,  6,  8,  0, 13,  3,  4, 14,  7,  5, 11},
       {10, 15,  4,  2,  7, 12,  9,  5,  6,  1, 13, 14,  0, 11,  3,  8},
       {9, 14, 15,  5,  2,  8, 12,  3,  7,  0,  4, 10,  1, 13, 11,  6},
       {4,  3,  2, 12,  9,  5, 15, 10, 11, 14,  1,  7,  6,  0,  8, 13}},

      {{4, 11,  2, 14, 15,  0,  8, 13,  3, 12,  9,  7,  5, 10,  6,  1},
       {13,  0, 11,  7,  4,  9,  1, 10, 14,  3,  5, 12,  2, 15,  8,  6},
       {1,  4, 11, 13, 12,  3,  7, 14, 10, 15,  6,  8,  0,  5,  9,  2},
       {6, 11, 13,  8,  1,  4, 10,  7,  9,  5,  0, 15, 14,  2,  3, 12}},

      {{13,  2,  8,  4,  6, 15, 11,  1, 10,  9,  3, 14,  5,  0, 12,  7},
       {1, 15, 13,  8, 10,  3,  7,  4, 12,  5,  6, 11,  0, 14,  9,  2},
       {7, 11,  4,  1,  9, 12, 14,  2,  0,  6, 10, 13, 15,  3,  5,  8},
       {2,  1, 14,  7,  4, 10,  8, 13, 15, 12,  9,  0,  3,  5,  6, 11}}};

static void permute(char *out, char *in, uchar *p, int n)
{
      int i;
      for (i=0;i<n;i++)
            out[i] = in[p[i]-1];
}

static void lshift(char *d, int count, int n)
{
      char out[64];
      int i;
      for (i=0;i<n;i++)
            out[i] = d[(i+count)%n];
      for (i=0;i<n;i++)
            d[i] = out[i];
}

static void concat(char *out, char *in1, char *in2, int l1, int l2)
{
      while (l1--)
            *out++ = *in1++;
      while (l2--)
            *out++ = *in2++;
}

static void xor(char *out, char *in1, char *in2, int n)
{
      int i;
      for (i=0;i<n;i++)
            out[i] = in1[i] ^ in2[i];
}

static void dohash(char *out, char *in, char *key, int forw)
{
      int i, j, k;
      char pk1[56];
      char c[28];
      char d[28];
      char cd[56];
      char ki[16][48];
      char pd1[64];
      char l[32], r[32];
      char rl[64];

      permute(pk1, key, perm1, 56);

      for (i=0;i<28;i++)
            c[i] = pk1[i];
      for (i=0;i<28;i++)
            d[i] = pk1[i+28];

      for (i=0;i<16;i++) {
            lshift(c, sc[i], 28);
            lshift(d, sc[i], 28);

            concat(cd, c, d, 28, 28); 
            permute(ki[i], cd, perm2, 48); 
      }

      permute(pd1, in, perm3, 64);

      for (j=0;j<32;j++) {
            l[j] = pd1[j];
            r[j] = pd1[j+32];
      }

      for (i=0;i<16;i++) {
            char er[48];
            char erk[48];
            char b[8][6];
            char cb[32];
            char pcb[32];
            char r2[32];

            permute(er, r, perm4, 48);

            xor(erk, er, ki[forw ? i : 15 - i], 48);

            for (j=0;j<8;j++)
                  for (k=0;k<6;k++)
                        b[j][k] = erk[j*6 + k];

            for (j=0;j<8;j++) {
                  int m, n;
                  m = (b[j][0]<<1) | b[j][5];

                  n = (b[j][1]<<3) | (b[j][2]<<2) | (b[j][3]<<1) | b[j][4]; 

                  for (k=0;k<4;k++) 
                        b[j][k] = (sbox[j][m][n] & (1<<(3-k)))?1:0; 
            }

            for (j=0;j<8;j++)
                  for (k=0;k<4;k++)
                        cb[j*4+k] = b[j][k];
            permute(pcb, cb, perm5, 32);

            xor(r2, l, pcb, 32);

            for (j=0;j<32;j++)
                  l[j] = r[j];

            for (j=0;j<32;j++)
                  r[j] = r2[j];
      }

      concat(rl, r, l, 32, 32);

      permute(out, rl, perm6, 64);
}

static void str_to_key(unsigned char *str,unsigned char *key)
{
      int i;

      key[0] = str[0]>>1;
      key[1] = ((str[0]&0x01)<<6) | (str[1]>>2);
      key[2] = ((str[1]&0x03)<<5) | (str[2]>>3);
      key[3] = ((str[2]&0x07)<<4) | (str[3]>>4);
      key[4] = ((str[3]&0x0F)<<3) | (str[4]>>5);
      key[5] = ((str[4]&0x1F)<<2) | (str[5]>>6);
      key[6] = ((str[5]&0x3F)<<1) | (str[6]>>7);
      key[7] = str[6]&0x7F;
      for (i=0;i<8;i++) {
            key[i] = (key[i]<<1);
      }
}


static void smbhash(unsigned char *out, unsigned char *in, unsigned char *key, int forw)
{
      int i;
      char outb[64];
      char inb[64];
      char keyb[64];
      unsigned char key2[8];

      str_to_key(key, key2);

      for (i=0;i<64;i++) {
            inb[i] = (in[i/8] & (1<<(7-(i%8)))) ? 1 : 0;
            keyb[i] = (key2[i/8] & (1<<(7-(i%8)))) ? 1 : 0;
            outb[i] = 0;
      }

      dohash(outb, inb, keyb, forw);

      for (i=0;i<8;i++) {
            out[i] = 0;
      }

      for (i=0;i<64;i++) {
            if (outb[i])
                  out[i/8] |= (1<<(7-(i%8)));
      }
}

void E_P16(unsigned char *p14,unsigned char *p16)
{
      unsigned char sp8[8] = {0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25};
      smbhash(p16, sp8, p14, 1);
      smbhash(p16+8, sp8, p14+7, 1);
}

void E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24)
{
      smbhash(p24, c8, p21, 1);
      smbhash(p24+8, c8, p21+7, 1);
      smbhash(p24+16, c8, p21+14, 1);
}

void D_P16(unsigned char *p14, unsigned char *in, unsigned char *out)
{
      smbhash(out, in, p14, 0);
        smbhash(out+8, in+8, p14+7, 0);
}

void E_old_pw_hash( unsigned char *p14, unsigned char *in, unsigned char *out)
{
        smbhash(out, in, p14, 1);
        smbhash(out+8, in+8, p14+7, 1);
}

void cred_hash1(unsigned char *out,unsigned char *in,unsigned char *key)
{
      unsigned char buf[8];

      smbhash(buf, in, key, 1);
      smbhash(out, buf, key+9, 1);
}

void cred_hash2(unsigned char *out,unsigned char *in,unsigned char *key)
{
      unsigned char buf[8];
      static unsigned char key2[8];

      smbhash(buf, in, key, 1);
      key2[0] = key[7];
      smbhash(out, buf, key2, 1);
}

void cred_hash3(unsigned char *out,unsigned char *in,unsigned char *key, int forw)
{
        static unsigned char key2[8];

        smbhash(out, in, key, forw);
        key2[0] = key[7];
        smbhash(out + 8, in + 8, key2, forw);
}

void SamOEMhash( unsigned char *data, unsigned char *key, int val)
{
  unsigned char s_box[256];
  unsigned char index_i = 0;
  unsigned char index_j = 0;
  unsigned char j = 0;
  int ind;

  for (ind = 0; ind < 256; ind++)
  {
    s_box[ind] = (unsigned char)ind;
  }

  for( ind = 0; ind < 256; ind++)
  {
     unsigned char tc;

     j += (s_box[ind] + key[ind%16]);

     tc = s_box[ind];
     s_box[ind] = s_box[j];
     s_box[j] = tc;
  }
  for( ind = 0; ind < (val ? 516 : 16); ind++)
  {
    unsigned char tc;
    unsigned char t;

    index_i++;
    index_j += s_box[index_i];

    tc = s_box[index_i];
    s_box[index_i] = s_box[index_j];
    s_box[index_j] = tc;

    t = s_box[index_i] + s_box[index_j];
    data[ind] = data[ind] ^ s_box[t];
  }
}

/* 
   Unix SMB/Netbios implementation.
   Version 1.9.
   SMB parameters and setup
   Copyright (C) Andrew Tridgell 1992-1998
   Modified by Jeremy Allison 1995.
   
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
   
   This program 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 General Public License for more details.
   
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/****************************************************************************
 Like strncpy but always null terminates. Make sure there is room!
 The variable n should always be one less than the available size.
****************************************************************************/

static char*
StrnCpy(char *dest,const char *src, size_t n)
{
  char *d = dest;
  if (!dest) return(NULL);
  if (!src) {
    *dest = 0;
    return(dest);
  }
  while (n-- && (*d++ = *src++)) ;
  *d = 0;
  return(dest);
}

static size_t
skip_multibyte_char (char c)
{
return 0;
}



static void
strupper (char *s)
{
while (*s)
  {
    {
    size_t skip = skip_multibyte_char( *s );
    if( skip != 0 )
      s += skip;
    else
      {
      if (islower((unsigned char)*s))
      *s = toupper(*s);
      s++;
      }
    }
  }
}

extern void SMBOWFencrypt(uchar passwd[16], uchar *c8, uchar p24[24]);

/*
 This implements the X/Open SMB password encryption
 It takes a password, a 8 byte "crypt key" and puts 24 bytes of 
 encrypted password into p24 
 */

void
SMBencrypt(const uchar *passwd, uchar *c8, uchar *p24)
  {
  uchar p14[15], p21[21];
  
  memset(p21,'\0',21);
  memset(p14,'\0',14);
  StrnCpy((char *)p14,(char *)passwd,14);
  
  strupper((char *)p14);
  E_P16(p14, p21); 
  
  SMBOWFencrypt(p21, c8, p24);
  
#ifdef DEBUG_PASSWORD
  DEBUG(100,("SMBencrypt: lm#, challenge, response\n"));
  dump_data(100, (char *)p21, 16);
  dump_data(100, (char *)c8, 8);
  dump_data(100, (char *)p24, 24);
#endif
  }

/* Routines for Windows NT MD4 Hash functions. */
static int _my_wcslen(int16 *str)
{
      int len = 0;
      while(*str++ != 0)
            len++;
      return len;
}

/*
 * Convert a string into an NT UNICODE string.
 * Note that regardless of processor type 
 * this must be in intel (little-endian)
 * format.
 */
 
static int _my_mbstowcs(int16 *dst, const uchar *src, int len)
{
      int i;
      int16 val;
 
      for(i = 0; i < len; i++) {
            val = *src;
            SSVAL(dst,0,val);
            dst++;
            src++;
            if(val == 0)
                  break;
      }
      return i;
}

/* 
 * Creates the MD4 Hash of the users password in NT UNICODE.
 */
 
static void
E_md4hash(const uchar *passwd, uchar *p16)
{
      int len;
      int16 wpwd[129];
      
      /* Password cannot be longer than 128 characters */
      len = strlen((char *)passwd);
      if(len > 128)
            len = 128;
      /* Password must be converted to NT unicode */
      _my_mbstowcs(wpwd, passwd, len);
      wpwd[len] = 0; /* Ensure string is null terminated */
      /* Calculate length in bytes */
      len = _my_wcslen(wpwd) * sizeof(int16);

      mdfour(p16, (unsigned char *)wpwd, len);
}


/* Does the des encryption from the NT or LM MD4 hash. */
void SMBOWFencrypt(uchar passwd[16], uchar *c8, uchar p24[24])
{
      uchar p21[21];
 
      memset(p21,'\0',21);
 
      memcpy(p21, passwd, 16);    
      E_P24(p21, c8, p24);
}



/* Does the NT MD4 hash then des encryption. */
 
void SMBNTencrypt(const uchar *passwd, uchar *c8, uchar *p24)
{
      uchar p21[21];
 
      memset(p21,'\0',21);
 
      E_md4hash(passwd, p21);    
      SMBOWFencrypt(p21, c8, p24);

#ifdef DEBUG_PASSWORD
      DEBUG(100,("SMBNTencrypt: nt#, challenge, response\n"));
      dump_data(100, (char *)p21, 16);
      dump_data(100, (char *)c8, 8);
      dump_data(100, (char *)p24, 24);
#endif
}

#if 0

BOOL make_oem_passwd_hash(char data[516], const char *passwd, uchar old_pw_hash[16], BOOL unicode)
{
      int new_pw_len = strlen(passwd) * (unicode ? 2 : 1);

      if (new_pw_len > 512)
      {
            DEBUG(0,("make_oem_passwd_hash: new password is too long.\n"));
            return False;
      }

      /*
       * Now setup the data area.
       * We need to generate a random fill
       * for this area to make it harder to
       * decrypt. JRA.
       */
      generate_random_buffer((unsigned char *)data, 516, False);
      if (unicode)
      {
            struni2( &data[512 - new_pw_len], passwd);
      }
      else
      {
            fstrcpy( &data[512 - new_pw_len], passwd);
      }
      SIVAL(data, 512, new_pw_len);

#ifdef DEBUG_PASSWORD
      DEBUG(100,("make_oem_passwd_hash\n"));
      dump_data(100, data, 516);
#endif
      SamOEMhash( (unsigned char *)data, (unsigned char *)old_pw_hash, True);

      return True;
}

#endif
/* 
   Unix SMB/Netbios implementation.
   Version 1.9.
   a implementation of MD4 designed for use in the SMB authentication protocol
   Copyright (C) Andrew Tridgell 1997-1998.
   
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
   
   This program 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 General Public License for more details.
   
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/* NOTE: This code makes no attempt to be fast! 

   It assumes that a int is at least 32 bits long
*/

static uint32 A, B, C, D;

static uint32 F(uint32 X, uint32 Y, uint32 Z)
{
      return (X&Y) | ((~X)&Z);
}

static uint32 G(uint32 X, uint32 Y, uint32 Z)
{
      return (X&Y) | (X&Z) | (Y&Z); 
}

static uint32 H(uint32 X, uint32 Y, uint32 Z)
{
      return X^Y^Z;
}

static uint32 lshift_a(uint32 x, int s)
{
      x &= 0xFFFFFFFF;
      return ((x<<s)&0xFFFFFFFF) | (x>>(32-s));
}

#define ROUND1(a,b,c,d,k,s) a = lshift_a(a + F(b,c,d) + X[k], s)
#define ROUND2(a,b,c,d,k,s) a = lshift_a(a + G(b,c,d) + X[k] + (uint32)0x5A827999,s)
#define ROUND3(a,b,c,d,k,s) a = lshift_a(a + H(b,c,d) + X[k] + (uint32)0x6ED9EBA1,s)

/* this applies md4 to 64 byte chunks */
static void mdfour64(uint32 *M)
{
      int j;
      uint32 AA, BB, CC, DD;
      uint32 X[16];

      for (j=0;j<16;j++)
            X[j] = M[j];

      AA = A; BB = B; CC = C; DD = D;

        ROUND1(A,B,C,D,  0,  3);  ROUND1(D,A,B,C,  1,  7);  
      ROUND1(C,D,A,B,  2, 11);  ROUND1(B,C,D,A,  3, 19);
        ROUND1(A,B,C,D,  4,  3);  ROUND1(D,A,B,C,  5,  7);  
      ROUND1(C,D,A,B,  6, 11);  ROUND1(B,C,D,A,  7, 19);
        ROUND1(A,B,C,D,  8,  3);  ROUND1(D,A,B,C,  9,  7);  
      ROUND1(C,D,A,B, 10, 11);  ROUND1(B,C,D,A, 11, 19);
        ROUND1(A,B,C,D, 12,  3);  ROUND1(D,A,B,C, 13,  7);  
      ROUND1(C,D,A,B, 14, 11);  ROUND1(B,C,D,A, 15, 19);    

        ROUND2(A,B,C,D,  0,  3);  ROUND2(D,A,B,C,  4,  5);  
      ROUND2(C,D,A,B,  8,  9);  ROUND2(B,C,D,A, 12, 13);
        ROUND2(A,B,C,D,  1,  3);  ROUND2(D,A,B,C,  5,  5);  
      ROUND2(C,D,A,B,  9,  9);  ROUND2(B,C,D,A, 13, 13);
        ROUND2(A,B,C,D,  2,  3);  ROUND2(D,A,B,C,  6,  5);  
      ROUND2(C,D,A,B, 10,  9);  ROUND2(B,C,D,A, 14, 13);
        ROUND2(A,B,C,D,  3,  3);  ROUND2(D,A,B,C,  7,  5);  
      ROUND2(C,D,A,B, 11,  9);  ROUND2(B,C,D,A, 15, 13);

      ROUND3(A,B,C,D,  0,  3);  ROUND3(D,A,B,C,  8,  9);  
      ROUND3(C,D,A,B,  4, 11);  ROUND3(B,C,D,A, 12, 15);
        ROUND3(A,B,C,D,  2,  3);  ROUND3(D,A,B,C, 10,  9);  
      ROUND3(C,D,A,B,  6, 11);  ROUND3(B,C,D,A, 14, 15);
        ROUND3(A,B,C,D,  1,  3);  ROUND3(D,A,B,C,  9,  9);  
      ROUND3(C,D,A,B,  5, 11);  ROUND3(B,C,D,A, 13, 15);
        ROUND3(A,B,C,D,  3,  3);  ROUND3(D,A,B,C, 11,  9);  
      ROUND3(C,D,A,B,  7, 11);  ROUND3(B,C,D,A, 15, 15);

      A += AA; B += BB; C += CC; D += DD;
      
      A &= 0xFFFFFFFF; B &= 0xFFFFFFFF;
      C &= 0xFFFFFFFF; D &= 0xFFFFFFFF;

      for (j=0;j<16;j++)
            X[j] = 0;
}

static void copy64(uint32 *M, const unsigned char *in)
{
      int i;

      for (i=0;i<16;i++)
            M[i] = (in[i*4+3]<<24) | (in[i*4+2]<<16) |
                  (in[i*4+1]<<8) | (in[i*4+0]<<0);
}

static void copy4(unsigned char *out,uint32 x)
{
      out[0] = x&0xFF;
      out[1] = (x>>8)&0xFF;
      out[2] = (x>>16)&0xFF;
      out[3] = (x>>24)&0xFF;
}

/* produce a md4 message digest from data of length n bytes */
void mdfour(unsigned char *out, const unsigned char *in, int n)
{
      unsigned char buf[128];
      uint32 M[16];
      uint32 b = n * 8;
      int i;

      A = 0x67452301;
      B = 0xefcdab89;
      C = 0x98badcfe;
      D = 0x10325476;

      while (n > 64) {
            copy64(M, in);
            mdfour64(M);
            in += 64;
            n -= 64;
      }

      for (i=0;i<128;i++)
            buf[i] = 0;
      memcpy(buf, in, n);
      buf[n] = 0x80;
      
      if (n <= 55) {
            copy4(buf+56, b);
            copy64(M, buf);
            mdfour64(M);
      } else {
            copy4(buf+120, b); 
            copy64(M, buf);
            mdfour64(M);
            copy64(M, buf+64);
            mdfour64(M);
      }

      for (i=0;i<128;i++)
            buf[i] = 0;
      copy64(M, buf);

      copy4(out, A);
      copy4(out+4, B);
      copy4(out+8, C);
      copy4(out+12, D);

      A = B = C = D = 0;
}


char versionString[] ="libntlm version 0.21";

/* Utility routines that handle NTLM auth structures. */

/* The [IS]VAL macros are to take care of byte order for non-Intel
 * Machines -- I think this file is OK, but it hasn't been tested.
 * The other files (the ones stolen from Samba) should be OK.
 */


/* 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) \
{ \
if (buf && count) \
  { \
  SSVAL(&ptr->header.len,0,count); \
  SSVAL(&ptr->header.maxlen,0,count); \
  SIVAL(&ptr->header.offset,0,((ptr->buffer - ((uint8*)ptr)) + ptr->bufIndex)); \
  memcpy(ptr->buffer+ptr->bufIndex, buf, count); \
  ptr->bufIndex += count; \
  } \
else \
  { \
  ptr->header.len = \
  ptr->header.maxlen = 0; \
  SIVAL(&ptr->header.offset,0,ptr->bufIndex); \
  } \
}

#define AddString(ptr, header, string) \
{ \
const char *p = string; \
int len = 0; \
if (p) len = strlen(p); \
AddBytes(ptr, header, ((const unsigned char*)p), len); \
}

#define AddUnicodeString(ptr, header, string) \
{ \
const char *p = string; \
unsigned char *b = NULL; \
int len = 0; \
if (p) \
  { \
  len = strlen(p); \
  b = strToUnicode(p); \
  } \
AddBytes(ptr, header, b, len*2); \
}


#define GetUnicodeString(structPtr, header) \
unicodeToString(((char*)structPtr) + IVAL(&structPtr->header.offset,0) , SVAL(&structPtr->header.len,0)/2)


static char *unicodeToString(char *p, size_t len)
  {
  int i;
  static char buf[1024];

  assert(len+1 < sizeof buf);
  
  for (i=0; i<len; ++i)
    {  
    buf[i] = *p & 0x7f;
    p += 2;
    }

  buf[i] = '\0';
  return buf;
  }

static unsigned char *strToUnicode(const char *p)
  {
  static unsigned char buf[1024];
  size_t l = strlen(p);
  int i = 0;
  
  assert(l*2 < sizeof buf);
  
  while (l--)
    {
    buf[i++] = *p++;
    buf[i++] = 0;
    }
  
  return buf;
  }


void spa_build_auth_request (SPAAuthRequest *request, const char *user, const char *domain)
  {
    char *u = strdup(user);
    char *p = strchr(u,'@');
    
    if (p)
      {
        if (!domain) 
          domain = p+1;
        *p = '\0';
      }
    
    request->bufIndex = 0;
    memcpy(request->ident,"NTLMSSP\0\0\0",8);
    SIVAL(&request->msgType,0,1);
    SIVAL(&request->flags,0,0x0000b207);  /* have to figure out what these mean */
    AddString(request,user,u);
    AddString(request,domain,domain);
    free(u);
  }

void spa_build_auth_response (SPAAuthChallenge *challenge, SPAAuthResponse *response, const char *user, const char *password)
  {
    uint8 lmRespData[24];
    uint8 ntRespData[24];
    char *d = strdup(GetUnicodeString(challenge,uDomain));
    char *domain = d;
    char *u = strdup(user);
    char *p = strchr(u,'@');
    
    if (p)
      {
        domain = p+1;
        *p = '\0';
      }
    
    SMBencrypt(password,   challenge->challengeData, lmRespData);
    SMBNTencrypt(password, challenge->challengeData, ntRespData);
    
    response->bufIndex = 0;
    memcpy(response->ident,"NTLMSSP\0\0\0",8);
    SIVAL(&response->msgType,0,3);
    
    AddBytes(response,lmResponse,lmRespData,24);
    AddBytes(response,ntResponse,ntRespData,24);
    AddUnicodeString(response,uDomain,domain);
    AddUnicodeString(response,uUser,u);
    AddUnicodeString(response,uWks,u);
    AddString(response,sessionKey,NULL);
  
    response->flags = challenge->flags;
    
    free(d);
    free(u);
  }


Generated by  Doxygen 1.6.0   Back to index