commit: r1650 - neon/trunk/src

Kai.Sommerfeld at Sun.COM Kai.Sommerfeld at Sun.COM
Thu Mar 26 08:56:24 EDT 2009


Author: kso
Date: Thu Mar 26 05:24:32 2009
New Revision: 1650

Added:
   neon/trunk/src/ne_ntlm.c
   neon/trunk/src/ne_ntlm.h
Modified:
   neon/trunk/src/ne_auth.c

Log:
initial support for platform-independent NTLM auth

Modified: neon/trunk/src/ne_auth.c
==============================================================================
--- neon/trunk/src/ne_auth.c	(original)
+++ neon/trunk/src/ne_auth.c	Thu Mar 26 05:24:32 2009
@@ -77,6 +77,10 @@
 #include "ne_sspi.h"
 #endif
 
+#ifdef HAVE_NTLM
+#include "ne_ntlm.h"
+#endif
+ 
 #define HOOK_SERVER_ID "http://webdav.org/neon/hooks/server-auth"
 #define HOOK_PROXY_ID "http://webdav.org/neon/hooks/proxy-auth"
 
@@ -173,6 +177,10 @@
     char *sspi_token;
     void *sspi_context;
 #endif
+#ifdef HAVE_NTLM
+     /* This is used for NTLM auth */
+     ne_ntlm_context *ntlm_context;
+#endif
     /* These all used for Digest auth */
     char *realm;
     char *nonce;
@@ -287,6 +295,11 @@
     ne_sspi_destroy_context(sess->sspi_context);
     sess->sspi_context = NULL;
 #endif
+#ifdef HAVE_NTLM
+    ne_ntlm_destroy_context(sess->ntlm_context);
+    sess->ntlm_context = NULL;
+#endif
+
     sess->protocol = NULL;
 }
 
@@ -688,6 +701,61 @@
     return invalid;
 }
 
+#ifdef HAVE_NTLM
+
+static char *request_ntlm(auth_session *sess, struct auth_request *request) 
+{
+    char *token = ne_ntlm_getRequestToken(sess->ntlm_context);
+    if (token) {
+        char * req = ne_concat(sess->protocol->name, " ", token, "\r\n", NULL);
+        ne_free(token);
+        return req;
+    } else {
+        return NULL;
+    }
+}
+
+static int ntlm_challenge(auth_session *sess, int attempt,
+                          struct auth_challenge *parms,
+                          ne_buffer **errmsg) 
+{
+    int status;
+    
+    NE_DEBUG(NE_DBG_HTTPAUTH, "auth: NTLM challenge.\n");
+    
+    if (!parms->opaque) {
+        char password[NE_ABUFSIZ];
+
+        if (get_credentials(sess, errmsg, attempt, parms, password)) {
+           /* Failed to get credentials */
+           return -1;
+        }
+
+        if (sess->ntlm_context) {
+           status = ne_ntlm_destroy_context(sess->ntlm_context);
+           sess->ntlm_context = NULL;
+           if (status) {
+               return status;
+           }
+        }
+
+        status = ne_ntlm_create_context(&sess->ntlm_context,
+                                        sess->username, 
+                                        password);
+        if (status) {
+            return status;
+        }
+    }
+
+    status = ne_ntlm_authenticate(sess->ntlm_context, parms->opaque);
+    if (status) {
+        return status;
+    }
+
+    return 0;
+}
+#endif /* HAVE_NTLM */
+  
 /* Examine a digest challenge: return 0 if it is a valid Digest challenge,
  * else non-zero. */
 static int digest_challenge(auth_session *sess, int attempt,
@@ -1138,6 +1206,11 @@
       sspi_challenge, request_sspi, NULL,
       AUTH_FLAG_OPAQUE_PARAM|AUTH_FLAG_VERIFY_NON40x|AUTH_FLAG_CONN_AUTH },
 #endif
+#ifdef HAVE_NTLM
+    { NE_AUTH_NEGOTIATE, 30, "NTLM",
+      ntlm_challenge, request_ntlm, NULL,
+      AUTH_FLAG_OPAQUE_PARAM|AUTH_FLAG_VERIFY_NON40x|AUTH_FLAG_CONN_AUTH },
+#endif
     { 0 }
 };
 
@@ -1435,6 +1508,11 @@
         ne_sspi_clear_context(sess->sspi_context);
     }
 #endif
+#ifdef HAVE_NTLM
+    if (sess->ntlm_context) {
+        ne_ntlm_clear_context(sess->ntlm_context);
+    }
+#endif
 
     return ret;
 }

Added: neon/trunk/src/ne_ntlm.c
==============================================================================
--- (empty file)
+++ neon/trunk/src/ne_ntlm.c	Thu Mar 26 05:24:32 2009
@@ -0,0 +1,700 @@
+/* 
+   Handling of NTLM Authentication
+   Copyright (C) 2003, Daniel Stenberg <daniel at haxx.se>
+   Copyright (C) 2009, Kai Sommerfeld <kso at openoffice.org>
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public
+   License as published by the Free Software Foundation; either
+   version 2 of the License, or (at your option) any later version.
+   
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with this library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+   MA 02111-1307, USA
+
+*/
+
+/* NTLM details:
+   
+   http://davenport.sourceforge.net/ntlm.html
+   http://www.innovation.ch/java/ntlm.html
+
+*/
+
+#include "ne_ntlm.h"
+
+#ifdef HAVE_NTLM
+
+#include "ne_string.h"
+
+typedef enum {
+  NTLMSTATE_NONE,
+  NTLMSTATE_TYPE1,
+  NTLMSTATE_TYPE2,
+  NTLMSTATE_TYPE3,
+  NTLMSTATE_LAST
+} NTLMState;
+
+struct ne_ntlm_context_s {
+  NTLMState state;
+  unsigned char nonce[8];
+  char *user;
+  char *passwd;
+  char *requestToken;
+};
+
+typedef enum {
+  NTLM_NONE, /* not a ntlm */
+  NTLM_BAD,  /* an ntlm, but one we don't like */
+  NTLM_FIRST, /* the first 401-reply we got with NTLM */
+  NTLM_FINE, /* an ntlm we act on */
+
+  NTLM_LAST  /* last entry in this enum, don't use */
+} ntlm;
+
+/* Flag bits definitions based on http://davenport.sourceforge.net/ntlm.html */
+
+#define NTLMFLAG_NEGOTIATE_UNICODE               (1<<0)
+/* Indicates that Unicode strings are supported for use in security buffer
+   data. */
+
+#define NTLMFLAG_NEGOTIATE_OEM                   (1<<1)
+/* Indicates that OEM strings are supported for use in security buffer data. */
+
+#define NTLMFLAG_REQUEST_TARGET                  (1<<2)
+/* Requests that the server's authentication realm be included in the Type 2
+   message. */
+
+/* unknown (1<<3) */
+#define NTLMFLAG_NEGOTIATE_SIGN                  (1<<4)
+/* Specifies that authenticated communication between the client and server
+   should carry a digital signature (message integrity). */
+
+#define NTLMFLAG_NEGOTIATE_SEAL                  (1<<5)
+/* Specifies that authenticated communication between the client and server
+   should be encrypted (message confidentiality). */
+
+#define NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE        (1<<6)
+/* unknown purpose */
+
+#define NTLMFLAG_NEGOTIATE_LM_KEY                (1<<7)
+/* Indicates that the LAN Manager session key should be used for signing and
+   sealing authenticated communications. */
+
+#define NTLMFLAG_NEGOTIATE_NETWARE               (1<<8)
+/* unknown purpose */
+
+#define NTLMFLAG_NEGOTIATE_NTLM_KEY              (1<<9)
+/* Indicates that NTLM authentication is being used. */
+
+/* unknown (1<<10) */
+/* unknown (1<<11) */
+
+#define NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED       (1<<12)
+/* Sent by the client in the Type 1 message to indicate that a desired
+   authentication realm is included in the message. */
+
+#define NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED  (1<<13)
+/* Sent by the client in the Type 1 message to indicate that the client
+   workstation's name is included in the message. */
+
+#define NTLMFLAG_NEGOTIATE_LOCAL_CALL            (1<<14)
+/* Sent by the server to indicate that the server and client are on the same
+   machine. Implies that the client may use a pre-established local security
+   context rather than responding to the challenge. */
+
+#define NTLMFLAG_NEGOTIATE_ALWAYS_SIGN           (1<<15)
+/* Indicates that authenticated communication between the client and server
+   should be signed with a "dummy" signature. */
+
+#define NTLMFLAG_TARGET_TYPE_DOMAIN              (1<<16)
+/* Sent by the server in the Type 2 message to indicate that the target
+   authentication realm is a domain. */
+
+#define NTLMFLAG_TARGET_TYPE_SERVER              (1<<17)
+/* Sent by the server in the Type 2 message to indicate that the target
+   authentication realm is a server. */
+
+#define NTLMFLAG_TARGET_TYPE_SHARE               (1<<18)
+/* Sent by the server in the Type 2 message to indicate that the target
+   authentication realm is a share. Presumably, this is for share-level
+   authentication. Usage is unclear. */
+
+#define NTLMFLAG_NEGOTIATE_NTLM2_KEY             (1<<19)
+/* Indicates that the NTLM2 signing and sealing scheme should be used for
+   protecting authenticated communications. */
+
+#define NTLMFLAG_REQUEST_INIT_RESPONSE           (1<<20)
+/* unknown purpose */
+
+#define NTLMFLAG_REQUEST_ACCEPT_RESPONSE         (1<<21)
+/* unknown purpose */
+
+#define NTLMFLAG_REQUEST_NONNT_SESSION_KEY       (1<<22)
+/* unknown purpose */
+
+#define NTLMFLAG_NEGOTIATE_TARGET_INFO           (1<<23)
+/* Sent by the server in the Type 2 message to indicate that it is including a
+   Target Information block in the message. */
+
+/* unknown (1<24) */
+/* unknown (1<25) */
+/* unknown (1<26) */
+/* unknown (1<27) */
+/* unknown (1<28) */
+
+#define NTLMFLAG_NEGOTIATE_128                   (1<<29)
+/* Indicates that 128-bit encryption is supported. */
+
+#define NTLMFLAG_NEGOTIATE_KEY_EXCHANGE          (1<<30)
+/* unknown purpose */
+
+#define NTLMFLAG_NEGOTIATE_56                    (1<<31)
+/* Indicates that 56-bit encryption is supported. */
+
+#ifdef HAVE_OPENSSL
+/* We need OpenSSL for the crypto lib to provide us with MD4 and DES */
+
+/* -- WIN32 approved -- */
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include <openssl/des.h>
+#include <openssl/md4.h>
+#include <openssl/ssl.h>
+
+#if OPENSSL_VERSION_NUMBER < 0x00907001L
+#define DES_key_schedule des_key_schedule
+#define DES_cblock des_cblock
+#define DES_set_odd_parity des_set_odd_parity
+#define DES_set_key des_set_key
+#define DES_ecb_encrypt des_ecb_encrypt
+
+/* This is how things were done in the old days */
+#define DESKEY(x) x
+#define DESKEYARG(x) x
+#else
+/* Modern version */
+#define DESKEYARG(x) *x
+#define DESKEY(x) &x
+#endif
+
+/* Define this to make the type-3 message include the NT response message */
+#define USE_NTRESPONSES 1
+
+/*
+  (*) = A "security buffer" is a triplet consisting of two shorts and one
+  long:
+
+  1. a 'short' containing the length of the buffer in bytes
+  2. a 'short' containing the allocated space for the buffer in bytes
+  3. a 'long' containing the offset to the start of the buffer from the
+     beginning of the NTLM message, in bytes.
+*/
+
+static ntlm ne_input_ntlm(ne_ntlm_context *ctx,
+			  const char *responseToken)
+{
+  if(responseToken) {
+    /* We got a type-2 message here:
+
+       Index   Description         Content
+       0       NTLMSSP Signature   Null-terminated ASCII "NTLMSSP"
+                                   (0x4e544c4d53535000)
+       8       NTLM Message Type   long (0x02000000)
+       12      Target Name         security buffer(*)
+       20      Flags               long
+       24      Challenge           8 bytes
+       (32)    Context (optional)  8 bytes (two consecutive longs)
+       (40)    Target Information  (optional) security buffer(*)
+       32 (48) start of data block
+    */
+    unsigned char * buffer = NULL;
+
+    int size = ne_unbase64(responseToken, &buffer);
+
+    ctx->state = NTLMSTATE_TYPE2; /* we got a type-2 */
+
+    if(size >= 48)
+      /* the nonce of interest is index [24 .. 31], 8 bytes */
+      memcpy(ctx->nonce, &buffer[24], 8);
+
+    /* at index decimal 20, there's a 32bit NTLM flag field */
+      
+    if (buffer) ne_free(buffer); 
+  }
+  else {
+    if(ctx->state >= NTLMSTATE_TYPE1)
+      return NTLM_BAD;
+
+    ctx->state = NTLMSTATE_TYPE1; /* we should sent away a type-1 */
+  }
+  return NTLM_FINE;
+}
+
+/*
+ * Turns a 56 bit key into the 64 bit, odd parity key and sets the key.  The
+ * key schedule ks is also set.
+ */
+static void setup_des_key(unsigned char *key_56,
+                          DES_key_schedule DESKEYARG(ks))
+{
+  DES_cblock key;
+
+  key[0] = key_56[0];
+  key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
+  key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
+  key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
+  key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
+  key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
+  key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
+  key[7] =  (key_56[6] << 1) & 0xFF;
+
+  DES_set_odd_parity(&key);
+  DES_set_key(&key, ks);
+}
+
+ /*
+  * takes a 21 byte array and treats it as 3 56-bit DES keys. The
+  * 8 byte plaintext is encrypted with each key and the resulting 24
+  * bytes are stored in the results array.
+  */
+static void calc_resp(unsigned char *keys,
+                      unsigned char *plaintext,
+                      unsigned char *results)
+{
+  DES_key_schedule ks;
+
+  setup_des_key(keys, DESKEY(ks));
+  DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) results,
+                  DESKEY(ks), DES_ENCRYPT);
+
+  setup_des_key(keys+7, DESKEY(ks));
+  DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+8),
+                  DESKEY(ks), DES_ENCRYPT);
+
+  setup_des_key(keys+14, DESKEY(ks));
+  DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+16),
+                  DESKEY(ks), DES_ENCRYPT);
+}
+
+/*
+ * Set up lanmanager and nt hashed passwords
+ */
+static void mkhash(char *password,
+                   unsigned char *nonce,  /* 8 bytes */
+                   unsigned char *lmresp  /* must fit 0x18 bytes */
+#ifdef USE_NTRESPONSES
+                   , unsigned char *ntresp  /* must fit 0x18 bytes */
+#endif
+  )
+{
+  unsigned char lmbuffer[21];
+#ifdef USE_NTRESPONSES
+  unsigned char ntbuffer[21];
+#endif
+  unsigned char *pw;
+  static const unsigned char magic[] = {
+    0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25
+  };
+  int i;
+  int len = strlen(password);
+
+  /* make it fit at least 14 bytes */
+  pw = malloc(len<7?14:len*2);
+  if(!pw)
+    return; /* this will lead to a badly generated package */
+
+  if (len > 14)
+    len = 14;
+  
+  for (i=0; i<len; i++)
+    pw[i] = toupper(password[i]);
+
+  for (; i<14; i++)
+    pw[i] = 0;
+
+  {
+    /* create LanManager hashed password */
+    DES_key_schedule ks;
+
+    setup_des_key(pw, DESKEY(ks));
+    DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)lmbuffer,
+                    DESKEY(ks), DES_ENCRYPT);
+  
+    setup_des_key(pw+7, DESKEY(ks));
+    DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)(lmbuffer+8),
+                    DESKEY(ks), DES_ENCRYPT);
+
+    memset(lmbuffer+16, 0, 5);
+  }
+  /* create LM responses */
+  calc_resp(lmbuffer, nonce, lmresp);
+
+#ifdef USE_NTRESPONSES
+  {
+    /* create NT hashed password */
+    MD4_CTX MD4;
+
+    len = strlen(password);
+
+    for (i=0; i<len; i++) {
+      pw[2*i]   = password[i];
+      pw[2*i+1] = 0;
+    }
+
+    MD4_Init(&MD4);
+    MD4_Update(&MD4, pw, 2*len);
+    MD4_Final(ntbuffer, &MD4);
+
+    memset(ntbuffer+16, 0, 8);
+  }
+
+  calc_resp(ntbuffer, nonce, ntresp);
+#endif
+
+  free(pw);
+}
+
+#define SHORTPAIR(x) ((x) & 0xff), ((x) >> 8)
+#define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8)&0xff), \
+  (((x) >>16)&0xff), ((x)>>24)
+
+/* this is for creating ntlm header output */
+static int ne_output_ntlm(ne_ntlm_context *ctx)
+{
+  const char *domain=""; /* empty */
+  const char *host=""; /* empty */
+  int domlen=strlen(domain);
+  int hostlen = strlen(host);
+  int hostoff; /* host name offset */
+  int domoff;  /* domain name offset */
+  int size;
+  unsigned char ntlmbuf[256]; /* enough, unless the host/domain is very long */
+
+  if(!ctx->user || !ctx->passwd)
+    /* no user, no auth */
+    return 0; /* OK */
+  
+  switch(ctx->state) {
+  case NTLMSTATE_TYPE1:
+  default: /* for the weird cases we (re)start here */
+    hostoff = 32;
+    domoff = hostoff + hostlen;
+    
+    /* Create and send a type-1 message:
+
+    Index Description          Content
+    0     NTLMSSP Signature    Null-terminated ASCII "NTLMSSP"
+                               (0x4e544c4d53535000)
+    8     NTLM Message Type    long (0x01000000)
+    12    Flags                long
+    16    Supplied Domain      security buffer(*)
+    24    Supplied Workstation security buffer(*)
+    32    start of data block
+
+    */
+
+    snprintf((char *)ntlmbuf, sizeof(ntlmbuf), "NTLMSSP%c"
+             "\x01%c%c%c" /* 32-bit type = 1 */
+             "%c%c%c%c"   /* 32-bit NTLM flag field */
+             "%c%c"  /* domain length */
+             "%c%c"  /* domain allocated space */
+             "%c%c"  /* domain name offset */
+             "%c%c"  /* 2 zeroes */
+             "%c%c"  /* host length */
+             "%c%c"  /* host allocated space */
+             "%c%c"  /* host name offset */
+             "%c%c"  /* 2 zeroes */
+             "%s"   /* host name */
+             "%s",  /* domain string */
+             0,     /* trailing zero */
+             0,0,0, /* part of type-1 long */
+
+             LONGQUARTET(
+               NTLMFLAG_NEGOTIATE_OEM|      /*   2 */
+               NTLMFLAG_NEGOTIATE_NTLM_KEY  /* 200 */
+               /* equals 0x0202 */
+               ),
+             SHORTPAIR(domlen),
+             SHORTPAIR(domlen),
+             SHORTPAIR(domoff),
+             0,0,
+             SHORTPAIR(hostlen),
+             SHORTPAIR(hostlen),
+             SHORTPAIR(hostoff),
+             0,0,
+             host, domain);
+
+    /* initial packet length */
+    size = 32 + hostlen + domlen;
+
+    /* now keeper of the base64 encoded package size */
+    if (ctx->requestToken) ne_free(ctx->requestToken);
+    ctx->requestToken = ne_base64(ntlmbuf, size);
+
+    break;
+    
+  case NTLMSTATE_TYPE2:
+    /* We received the type-2 already, create a type-3 message:
+
+    Index   Description            Content
+    0       NTLMSSP Signature      Null-terminated ASCII "NTLMSSP"
+                                   (0x4e544c4d53535000)
+    8       NTLM Message Type      long (0x03000000)
+    12      LM/LMv2 Response       security buffer(*)
+    20      NTLM/NTLMv2 Response   security buffer(*)
+    28      Domain Name            security buffer(*)
+    36      User Name              security buffer(*)
+    44      Workstation Name       security buffer(*)
+    (52)    Session Key (optional) security buffer(*)
+    (60)    Flags (optional)       long
+    52 (64) start of data block
+
+    */
+  
+  {
+    int lmrespoff;
+    int ntrespoff;
+    int useroff;
+    unsigned char lmresp[0x18]; /* fixed-size */
+#ifdef USE_NTRESPONSES
+    unsigned char ntresp[0x18]; /* fixed-size */
+#endif
+    const char *user;
+    int userlen;
+
+    user = strchr(ctx->user, '\\');
+    if(!user)
+      user = strchr(ctx->user, '/');
+
+    if (user) {
+      domain = ctx->user;
+      domlen = user - domain;
+      user++;
+    }
+    else
+      user = ctx->user;
+    userlen = strlen(user);
+
+    mkhash(ctx->passwd, &ctx->nonce[0], lmresp
+#ifdef USE_NTRESPONSES
+           , ntresp
+#endif
+      );
+
+    domoff = 64; /* always */
+    useroff = domoff + domlen;
+    hostoff = useroff + userlen;
+    lmrespoff = hostoff + hostlen;
+    ntrespoff = lmrespoff + 0x18;
+
+    /* Create the big type-3 message binary blob */
+    size = snprintf((char *)ntlmbuf, sizeof(ntlmbuf),
+                    "NTLMSSP%c"
+                    "\x03%c%c%c" /* type-3, 32 bits */
+
+                    "%c%c%c%c" /* LanManager length + allocated space */
+                    "%c%c" /* LanManager offset */
+                    "%c%c" /* 2 zeroes */
+
+                    "%c%c" /* NT-response length */
+                    "%c%c" /* NT-response allocated space */
+                    "%c%c" /* NT-response offset */
+                    "%c%c" /* 2 zeroes */
+                    
+                    "%c%c"  /* domain length */
+                    "%c%c"  /* domain allocated space */
+                    "%c%c"  /* domain name offset */
+                    "%c%c"  /* 2 zeroes */
+                    
+                    "%c%c"  /* user length */
+                    "%c%c"  /* user allocated space */
+                    "%c%c"  /* user offset */
+                    "%c%c"  /* 2 zeroes */
+                    
+                    "%c%c"  /* host length */
+                    "%c%c"  /* host allocated space */
+                    "%c%c"  /* host offset */
+                    "%c%c%c%c%c%c"  /* 6 zeroes */
+                    
+                    "\xff\xff"  /* message length */
+                    "%c%c"  /* 2 zeroes */
+                    
+                    "\x01\x82" /* flags */
+                    "%c%c"  /* 2 zeroes */
+
+                    /* domain string */
+                    /* user string */
+                    /* host string */
+                    /* LanManager response */
+                    /* NT response */
+                    ,
+                    0, /* zero termination */
+                    0,0,0, /* type-3 long, the 24 upper bits */
+
+                    SHORTPAIR(0x18),  /* LanManager response length, twice */
+                    SHORTPAIR(0x18),
+                    SHORTPAIR(lmrespoff),
+                    0x0, 0x0,
+                    
+#ifdef USE_NTRESPONSES
+                    SHORTPAIR(0x18),  /* NT-response length, twice */
+                    SHORTPAIR(0x18),
+#else
+                    0x0, 0x0,
+                    0x0, 0x0,
+#endif
+                    SHORTPAIR(ntrespoff),
+                    0x0, 0x0,
+
+                    SHORTPAIR(domlen),
+                    SHORTPAIR(domlen),
+                    SHORTPAIR(domoff),
+                    0x0, 0x0,
+
+                    SHORTPAIR(userlen),
+                    SHORTPAIR(userlen),
+                    SHORTPAIR(useroff),
+                    0x0, 0x0,
+                    
+                    SHORTPAIR(hostlen),
+                    SHORTPAIR(hostlen),
+                    SHORTPAIR(hostoff),
+                    0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+             
+                    0x0, 0x0,
+
+                    0x0, 0x0);
+
+    /* size is now 64 */
+    size=64;
+    ntlmbuf[62]=ntlmbuf[63]=0;
+
+    /* Make sure that the user and domain strings fit in the target buffer
+       before we copy them there. */
+    if(size + userlen + domlen >= sizeof(ntlmbuf)) {
+      return -1;
+    }
+
+    memcpy(&ntlmbuf[size], domain, domlen);
+    size += domlen;
+
+    memcpy(&ntlmbuf[size], user, userlen);
+    size += userlen;
+
+    /* we append the binary hashes to the end of the blob */
+    if(size < ((int)sizeof(ntlmbuf) - 0x18)) {
+      memcpy(&ntlmbuf[size], lmresp, 0x18);
+      size += 0x18;
+    }
+
+#ifdef USE_NTRESPONSES
+    if(size < ((int)sizeof(ntlmbuf) - 0x18)) {      
+      memcpy(&ntlmbuf[size], ntresp, 0x18);
+      size += 0x18;
+    }
+#endif
+
+    ntlmbuf[56] = size & 0xff;
+    ntlmbuf[57] = size >> 8;
+
+    /* convert the binary blob into base64 */
+    ctx->requestToken = ne_base64(ntlmbuf, size);
+
+    ctx->state = NTLMSTATE_TYPE3; /* we sent a type-3 */
+  }
+  break;
+
+  case NTLMSTATE_TYPE3:
+    /* connection is already authenticated,
+     * don't send a header in future requests */
+    if (ctx->requestToken) ne_free(ctx->requestToken);
+    ctx->requestToken = NULL;
+    break;
+  }
+
+  return 0; /* OK */
+}
+
+int ne_ntlm_create_context(ne_ntlm_context **context, const char *userName, const char *password)
+{
+    if (context == NULL) {
+	return -1;
+    } else {
+        ne_ntlm_context *ctx = ne_calloc(sizeof(ne_ntlm_context));
+
+	ctx->state = NTLMSTATE_NONE;
+	ctx->user = ne_strdup(userName);
+	ctx->passwd = ne_strdup(password);
+
+	*context = ctx;
+	return 0;
+    }
+}
+
+int ne_ntlm_destroy_context(ne_ntlm_context *context)
+{
+    if (context != NULL)  {
+        if (context->user)
+	    ne_free(context->user);
+
+	if (context->passwd)
+	    ne_free(context->passwd);
+
+	if (context->requestToken)
+	    ne_free(context->requestToken);
+
+	ne_free(context);
+    }
+    return 0;
+}
+
+int ne_ntlm_clear_context(ne_ntlm_context *context)
+{
+    return 0;
+}
+
+int ne_ntlm_authenticate(ne_ntlm_context *context, const char *responseToken)
+{
+    if (context == NULL) {
+	return -1;
+    } else {
+        if (context->state <= NTLMSTATE_TYPE3) {
+	  ntlm ntlmstatus = ne_input_ntlm(context, responseToken);
+
+	  if (ntlmstatus != NTLM_FINE) { 
+	    return -1;
+	  }
+	}
+    }
+    return ne_output_ntlm(context);
+}
+
+char *ne_ntlm_getRequestToken(ne_ntlm_context *context)
+{
+    if (context == NULL) {
+	return NULL;
+    } else {
+        if (context->requestToken) {
+	    char *ret = ne_strdup(context->requestToken);
+	    ne_free(context->requestToken);
+	    context->requestToken = NULL;
+	    return ret;
+	} else  {
+	  return NULL;
+	}
+    }
+}
+
+#endif /* HAVE_OPENSSL */
+#endif /* HAVE_NTLM */

Added: neon/trunk/src/ne_ntlm.h
==============================================================================
--- (empty file)
+++ neon/trunk/src/ne_ntlm.h	Thu Mar 26 05:24:32 2009
@@ -0,0 +1,44 @@
+/* 
+   Handling of NTLM Authentication
+   Copyright (C) 2009, Kai Sommerfeld <kso at openoffice.org>
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public
+   License as published by the Free Software Foundation; either
+   version 2 of the License, or (at your option) any later version.
+   
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with this library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+   MA 02111-1307, USA
+
+*/
+#ifndef NE_NTLM_H
+#define NE_NTLM_H
+
+#include "config.h"
+
+/* PRIVATE TO NEON -- NOT PART OF THE EXTERNAL API. */
+
+#ifdef HAVE_NTLM
+
+typedef struct ne_ntlm_context_s ne_ntlm_context;
+
+int ne_ntlm_create_context(ne_ntlm_context **context, const char *userName, const char *password);
+
+int ne_ntlm_destroy_context(ne_ntlm_context *context);
+
+int ne_ntlm_clear_context(ne_ntlm_context *context);
+
+int ne_ntlm_authenticate(ne_ntlm_context *context, const char *responseToken);
+
+char *ne_ntlm_getRequestToken(ne_ntlm_context *context);
+
+#endif /* HAVE_NTLM */
+
+#endif /* NE_NTLM_H */




More information about the neon-commits mailing list