Browse Source

Non working GSS-API implementation

Julien 'Lta' BALLET 11 years ago
parent
commit
b3384674f1
10 changed files with 305 additions and 42 deletions
  1. 15 13
      Makefile.am
  2. 2 0
      bin/dsm.c
  3. 2 2
      configure.ac
  4. 3 4
      include/bdsm/smb_defs.h
  5. 29 0
      include/bdsm/smb_gss.h
  6. 26 14
      include/bdsm/smb_packets.h
  7. 0 1
      include/bdsm/smb_session.h
  8. 8 0
      include/bdsm/smb_types.h
  9. 179 0
      src/smb_gss.c
  10. 41 8
      src/smb_session.c

+ 15 - 13
Makefile.am

@@ -4,7 +4,7 @@ DISTCLEANFILES = @DOLT_CLEANFILES@
 
 
 EXTRA_DIST =
 EXTRA_DIST =
 
 
-CFLAGS = -I$(top_srcdir)/contrib -I$(top_srcdir)/include @H5L_GSS_CFLAGS@
+CFLAGS = -I$(top_srcdir)/contrib -I$(top_srcdir)/include @TASN1_CFLAGS@
 
 
 if DEBUG
 if DEBUG
 AM_CFLAGS = -O0 -g3 -Wall #-Wextra
 AM_CFLAGS = -O0 -g3 -Wall #-Wextra
@@ -36,6 +36,7 @@ bdsm_HEADERS = \
 noinst_HEADERS = \
 noinst_HEADERS = \
     include/bdsm/smb_packets.h    \
     include/bdsm/smb_packets.h    \
     include/bdsm/smb_transport.h  \
     include/bdsm/smb_transport.h  \
+    include/bdsm/smb_gss.h        \
     contrib/mdx/md4.h             \
     contrib/mdx/md4.h             \
     contrib/mdx/md5.h
     contrib/mdx/md5.h
 
 
@@ -44,27 +45,28 @@ lib_LTLIBRARIES = libdsm.la
 libdsm_la_SOURCES = \
 libdsm_la_SOURCES = \
     contrib/mdx/md4.c   \
     contrib/mdx/md4.c   \
     contrib/mdx/md5.c   \
     contrib/mdx/md5.c   \
-    src/hmac_md5.c    \
+    src/hmac_md5.c      \
     src/netbios_ns.c    \
     src/netbios_ns.c    \
     src/netbios_ns_entry.c  \
     src/netbios_ns_entry.c  \
-    src/netbios_query.c   \
-    src/netbios_session.c \
-    src/netbios_utils.c   \
-    src/smb_fd.c   \
-    src/smb_file.c    \
+    src/netbios_query.c     \
+    src/netbios_session.c   \
+    src/netbios_utils.c     \
+    src/smb_fd.c        \
+    src/smb_file.c      \
+    src/smb_gss.c       \
     src/smb_message.c   \
     src/smb_message.c   \
-    src/smb_ntlm.c    \
+    src/smb_ntlm.c      \
     src/smb_session.c   \
     src/smb_session.c   \
-    src/smb_share.c   \
-    src/smb_stat.c    \
-    src/smb_trans2.c      \
-    src/smb_transport.c   \
+    src/smb_share.c     \
+    src/smb_stat.c      \
+    src/smb_trans2.c    \
+    src/smb_transport.c \
     src/smb_utils.c
     src/smb_utils.c
 
 
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = libdsm.pc
 pkgconfig_DATA = libdsm.pc
 
 
-libdsm_la_LDFLAGS = -version-info @BDSM_LIBTOOL_VERSION@ LTLIBICONV @H5L_GSS_LIBS@
+libdsm_la_LDFLAGS = -version-info @BDSM_LIBTOOL_VERSION@ LTLIBICONV @TASN1_LIBS@
 
 
 
 
 bin_PROGRAMS =
 bin_PROGRAMS =

+ 2 - 0
bin/dsm.c

@@ -131,6 +131,8 @@ int main(int ac, char **av)
 
 
   session = smb_session_new();
   session = smb_session_new();
 
 
+  //inet_aton("192.168.110.138", &addr.sin_addr);
+
   if (smb_session_connect(session, host, addr.sin_addr.s_addr, SMB_TRANSPORT_TCP))
   if (smb_session_connect(session, host, addr.sin_addr.s_addr, SMB_TRANSPORT_TCP))
   {
   {
     printf("Successfully connected to %s\n", host);
     printf("Successfully connected to %s\n", host);

+ 2 - 2
configure.ac

@@ -48,8 +48,8 @@ DOLT
 
 
 AC_CONFIG_MACRO_DIR([m4])
 AC_CONFIG_MACRO_DIR([m4])
 
 
-## Checks for Heimdal
-PKG_CHECK_MODULES([H5L_GSS], [heimdal-gssapi > 1.5])
+## Checks for the ASN.1 parser
+PKG_CHECK_MODULES([TASN1], [libtasn1])
 
 
 ## Checks for doxygen presence
 ## Checks for doxygen presence
 AC_CHECK_PROGS([DOXYGEN], [doxygen])
 AC_CHECK_PROGS([DOXYGEN], [doxygen])

+ 3 - 4
include/bdsm/smb_defs.h

@@ -67,7 +67,7 @@ enum
 
 
 enum smb_session_supports_what
 enum smb_session_supports_what
 {
 {
-  SMB_SESSION_EXT_SEC         = 0,
+  SMB_SESSION_XSEC            = 0,
 };
 };
 
 
 //-----------------------------------------------------------------------------/
 //-----------------------------------------------------------------------------/
@@ -202,7 +202,7 @@ enum smb_session_supports_what
 #define SMB_FLAG_NT_ERRORS      (1 << (14 + 8))
 #define SMB_FLAG_NT_ERRORS      (1 << (14 + 8))
 #define SMB_FLAG_EXECUTE_ONLY   (1 << (13 + 8))
 #define SMB_FLAG_EXECUTE_ONLY   (1 << (13 + 8))
 #define SMB_FLAG_DFS            (1 << (12 + 8))
 #define SMB_FLAG_DFS            (1 << (12 + 8))
-#define SMB_FLAG_EXT_SEC        (1 << (11 + 8))
+#define SMB_FLAG_XSEC           (1 << (11 + 8))
 #define SMB_FLAG_REPARSE_PATH   (1 << (10 + 8))
 #define SMB_FLAG_REPARSE_PATH   (1 << (10 + 8))
 #define SMB_FLAG_LONG_NAMES     (1 << (6 + 8))
 #define SMB_FLAG_LONG_NAMES     (1 << (6 + 8))
 #define SMB_FLAG_SIGN_REQUIRED  (1 << (4 + 8))
 #define SMB_FLAG_SIGN_REQUIRED  (1 << (4 + 8))
@@ -218,9 +218,8 @@ enum smb_session_supports_what
 #define SMB_CAPS_LARGE          (1 << 3)
 #define SMB_CAPS_LARGE          (1 << 3)
 #define SMB_CAPS_NTSMB          (1 << 4)
 #define SMB_CAPS_NTSMB          (1 << 4)
 #define SMB_CAPS_RPC            (1 << 5)
 #define SMB_CAPS_RPC            (1 << 5)
-#define SMB_CAPS_NTSTATUS       (1 << 6)
 #define SMB_CAPS_NTFIND         (1 << 9)
 #define SMB_CAPS_NTFIND         (1 << 9)
-#define SMB_CAPS_EXT_SEC        (1 << 31)
+#define SMB_CAPS_XSEC           (1 << 31)
 
 
 // File creation/open flags
 // File creation/open flags
 #define SMB_CREATE_OPLOCK       (1 << 1)
 #define SMB_CREATE_OPLOCK       (1 << 1)

+ 29 - 0
include/bdsm/smb_gss.h

@@ -0,0 +1,29 @@
+//---------------------------------------------------------------------------
+//  __________________    _________  _____            _____  .__         ._.
+//  \______   \______ \  /   _____/ /     \          /  _  \ |__| ____   | |
+//   |    |  _/|    |  \ \_____  \ /  \ /  \        /  /_\  \|  _/ __ \  | |
+//   |    |   \|    `   \/        /    Y    \      /    |    |  \  ___/   \|
+//   |______  /_______  /_______  \____|__  / /\   \____|__  |__|\___ |   __
+//          \/        \/        \/        \/  )/           \/        \/   \/
+//
+// This file is part of libdsm. Copyright © 2014 VideoLabs SAS
+//
+// Author: Julien 'Lta' BALLET <contact@lta.io>
+//
+// This program is free software. It comes without any warranty, to the extent
+// permitted by applicable law. You can redistribute it and/or modify it under
+// the terms of the Do What The Fuck You Want To Public License, Version 2, as
+// published by Sam Hocevar. See the COPYING file for more details.
+//----------------------------------------------------------------------------
+
+
+#ifndef __BDSM_SMB_GSS_H_
+#define __BDSM_SMB_GSS_H_
+
+#include "bdsm/smb_types.h"
+
+int             smb_session_login_gss(smb_session *s, const char *domain,
+                                      const char *user, const char *password);
+
+
+#endif

+ 26 - 14
include/bdsm/smb_packets.h

@@ -63,26 +63,38 @@ typedef struct
   uint16_t        bct;
   uint16_t        bct;
   char            dialects[];
   char            dialects[];
 
 
-} __attribute__((packed))   smb_negotiate_req;
+} __attribute__((packed))   smb_nego_req;
+
+
+#define SMB_NEGO_RESP_COMMON \
+  uint8_t         wct;            /* +-17 :) */                                \
+  uint16_t        dialect_index;                                               \
+  uint8_t         security_mode;  /* Share/User. Plaintext/Challenge */        \
+  uint32_t        diplodocus;                                                  \
+  uint32_t        max_bufsize;    /* Max buffer size requested by server. */   \
+  uint32_t        max_rawbuffer;  /* Max raw buffer size requested by serv. */ \
+  uint32_t        session_key;    /* 'MUST' be returned to server */           \
+  uint32_t        caps;                                                        \
+  uint64_t        ts;             /* I don't give a fuck (or do i?) */         \
+  uint16_t        tz;             /* Even less fuck given */                   \
+  uint8_t         key_length;     /* Size of challenge key // GSS blob */      \
+  uint16_t        bct;
 
 
 //<- Negotiate Protocol
 //<- Negotiate Protocol
 typedef struct
 typedef struct
 {
 {
-  uint8_t         wct;            // +-17 :)
-  uint16_t        dialect_index;  //
-  uint8_t         security_mode;  // Share/User. Plaintext/Challenge
-  uint32_t        diplodocus;
-  uint32_t        max_bufsize;    // Max buffer size requested by server.
-  uint32_t        max_rawbuffer;  // Max raw buffer size requested by serv.
-  uint32_t        session_key;    // 'MUST' be returned to server
-  uint32_t        caps;
-  uint64_t        ts;             // I don't give a fuck (or do i?)
-  uint16_t        tz;             // Even less fuck given
-  uint8_t         key_length;     // Size of challenge key, if != 8 then shit
-  uint16_t        bct;
+  SMB_NEGO_RESP_COMMON
   uint64_t        challenge;      // Normally 8 bytes, if not then wtf monkey
   uint64_t        challenge;      // Normally 8 bytes, if not then wtf monkey
   uint8_t         payload[];      // The rest isn't really meaningfull for us
   uint8_t         payload[];      // The rest isn't really meaningfull for us
-} __attribute__((packed))   smb_negotiate_resp;
+} __attribute__((packed))   smb_nego_resp;
+
+//<- Negotiate Protocol
+typedef struct
+{
+  SMB_NEGO_RESP_COMMON
+  uint8_t         srv_guid[16];
+  uint8_t         gssapi[];
+} __attribute__((packed))   smb_nego_xsec_resp;
 
 
 
 
 
 

+ 0 - 1
include/bdsm/smb_session.h

@@ -115,7 +115,6 @@ int             smb_session_connect(smb_session *s, const char *name,
  * @brief Authenticate on the remote host with the provided credentials
  * @brief Authenticate on the remote host with the provided credentials
  * @details Can be called if session state is SMB_STATE_DIALECT_OK.
  * @details Can be called if session state is SMB_STATE_DIALECT_OK.
  * If successfull, session state transition to SMB_STATE_SESSION_OK
  * If successfull, session state transition to SMB_STATE_SESSION_OK
- * @bug We currently only support LMv2 authentication.
  *
  *
  * @param s The session object.
  * @param s The session object.
  * @param domain The domain of the user. You should use the (netbios) uppercased
  * @param domain The domain of the user. You should use the (netbios) uppercased

+ 8 - 0
include/bdsm/smb_types.h

@@ -27,6 +27,9 @@
 #include <netinet/ip.h>
 #include <netinet/ip.h>
 #include <stddef.h>
 #include <stddef.h>
 
 
+#include <gssapi/gssapi_spnego.h>
+#include <gssapi/gssapi_ntlm.h>
+
 #include "bdsm/smb_packets.h"
 #include "bdsm/smb_packets.h"
 
 
 /**
 /**
@@ -112,6 +115,11 @@ typedef struct
     uint64_t            challenge;      // For challenge response security
     uint64_t            challenge;      // For challenge response security
     uint64_t            ts;             // It seems Win7 requires it :-/
     uint64_t            ts;             // It seems Win7 requires it :-/
   }                   srv;
   }                   srv;
+  struct {
+    gss_cred_id_t     credentials;
+    gss_ctx_id_t      ctx;
+    gss_buffer_desc   spnego;
+  }                   gss;              // eXtended SECurity negociation data
 
 
   smb_transport       transport;
   smb_transport       transport;
   struct smb_share_s  *shares;          // shares->files | Map fd <-> smb_file
   struct smb_share_s  *shares;          // shares->files | Map fd <-> smb_file

+ 179 - 0
src/smb_gss.c

@@ -0,0 +1,179 @@
+//---------------------------------------------------------------------------
+//  __________________    _________  _____            _____  .__         ._.
+//  \______   \______ \  /   _____/ /     \          /  _  \ |__| ____   | |
+//   |    |  _/|    |  \ \_____  \ /  \ /  \        /  /_\  \|  _/ __ \  | |
+//   |    |   \|    `   \/        /    Y    \      /    |    |  \  ___/   \|
+//   |______  /_______  /_______  \____|__  / /\   \____|__  |__|\___ |   __
+//          \/        \/        \/        \/  )/           \/        \/   \/
+//
+// This file is part of libdsm. Copyright © 2014 VideoLabs SAS
+//
+// Author: Julien 'Lta' BALLET <contact@lta.io>
+//
+// This program is free software. It comes without any warranty, to the extent
+// permitted by applicable law. You can redistribute it and/or modify it under
+// the terms of the Do What The Fuck You Want To Public License, Version 2, as
+// published by Sam Hocevar. See the COPYING file for more details.
+//----------------------------------------------------------------------------
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include "bdsm/debug.h"
+#include "bdsm/smb_session.h"
+#include "bdsm/smb_ntlm.h"
+
+void            smb_gss_display_status(OM_uint32 major,
+                                       OM_uint32 minor,
+                                       const gss_OID mech_type)
+{
+  OM_uint32 msg_ctx = 0, local_minor;
+  gss_buffer_desc maj_str, min_str;
+
+  do {
+    local_minor = minor;
+    gss_display_status(&local_minor, major, GSS_C_GSS_CODE,
+                       mech_type, &msg_ctx, &maj_str);
+    gss_display_status(&local_minor, minor, GSS_C_MECH_CODE,
+                       mech_type, &msg_ctx, &min_str);
+
+    BDSM_dbg("smb_gss_status: (0x%x, 0x%x) %.*s: %.*s\n", major, minor,
+             (int)maj_str.length,
+             (char *)maj_str.value,
+             (int)min_str.length,
+             (char *)min_str.value);
+
+    gss_release_buffer(&local_minor, &maj_str);
+    gss_release_buffer(&local_minor, &min_str);
+
+   } while (msg_ctx != 0);
+}
+
+int             smb_session_login_gss(smb_session *s, const char *domain,
+                                      const char *user, const char *password)
+{
+  OM_uint32         major_status, minor_status;
+  gss_name_t        gss_user, gss_server;
+  gss_OID_set_desc  mechs, *mechsp = GSS_C_NO_OID_SET;
+  gss_buffer_desc   input_buf, output_buf, tmp_buf;
+  gss_OID           req_mech_type, actual_mech_type;
+  gss_cred_id_t     creds;
+
+
+  assert(s != NULL && user != NULL && password != NULL);
+
+  //tmp_buf.value  = user;
+  asprintf(&tmp_buf.value, "%s\\%s", domain, user);
+  tmp_buf.length = strlen(tmp_buf.value);
+  gss_import_name(&minor_status, &tmp_buf, GSS_C_NT_USER_NAME, &gss_user);
+
+  //tmp_buf.value  = domain;
+  asprintf(&tmp_buf.value, "%s@%s", "smb", domain);
+  tmp_buf.length = strlen(tmp_buf.value);
+  gss_import_name(&minor_status, &tmp_buf, GSS_C_NT_HOSTBASED_SERVICE, &gss_server);
+
+  // We are using SPNEGO, so set this mech OID
+  mechs.elements = gss_mech_spnego;
+  mechs.count = 1;
+  mechsp = &mechs;
+
+  tmp_buf.value   = password;
+  tmp_buf.length  = strlen(password);
+
+  // major_status = gss_acquire_cred_with_password(&minor_status,
+  //                                               gss_user,
+  //                                               &tmp_buf,
+  //                                               GSS_C_INDEFINITE,
+  //                                               GSS_C_NO_OID_SET,
+  //                                               GSS_C_INITIATE,
+  //                                               &creds, NULL, NULL);
+  // smb_gss_display_status(major_status, minor_status, GSS_C_NO_OID);
+
+  major_status = gss_acquire_cred(&minor_status,
+                                  GSS_C_NO_NAME,
+                                  0,
+                                  GSS_C_NO_OID_SET,
+                                  GSS_C_INITIATE,
+                                  &creds, NULL, NULL);
+  smb_gss_display_status(major_status, minor_status, GSS_C_NO_OID);
+
+  input_buf.value   = NULL;
+  input_buf.length  = 0;
+
+  gss_OID_set supported;
+
+  req_mech_type = gss_mech_spnego;
+
+  gss_inquire_names_for_mech(&minor_status, gss_mech_spnego, &supported);
+
+  //gss_acquire_cred(cname, GSS_C_INITIATE);
+
+  major_status = gss_init_sec_context(&minor_status,
+    GSS_C_NO_CREDENTIAL,
+    &s->gss.ctx,
+    gss_server,
+    req_mech_type,
+    GSS_C_MUTUAL_FLAG | GSS_C_DELEG_FLAG,
+    GSS_C_INDEFINITE,
+    GSS_C_NO_CHANNEL_BINDINGS,
+    &input_buf,//&s->gss.spnego,
+    &actual_mech_type,
+    &output_buf,
+    NULL, NULL);
+  //major_status  = gss_accept_sec_conten
+
+  smb_gss_display_status(major_status, minor_status, req_mech_type);
+}
+
+int             smb_session_login_gss2(smb_session *s, const char *domain,
+                                      const char *user, const char *password)
+{
+  OM_uint32         major_status, minor_status;
+  gss_buffer_desc   user_buf, pass_buf;
+  gss_name_t        gss_user = GSS_C_NO_NAME;
+  gss_OID_set_desc  mechs, *mechsp = GSS_C_NO_OID_SET;
+
+
+  assert(s != NULL && user != NULL && password != NULL);
+
+  // We are using SPNEGO, so set this mech OID
+  mechs.elements = gss_mech_spnego;
+  mechs.count = 1;
+  mechsp = &mechs;
+
+  // Filling buffers with user and pass
+  user_buf.value  = user;
+  user_buf.length = strlen(user);
+  pass_buf.value  = password;
+  pass_buf.length = strlen(password);
+
+  major_status = gss_import_name(&minor_status, &user_buf,
+                                 (gss_OID) GSS_C_NT_USER_NAME, &gss_user);
+  if (major_status == GSS_S_COMPLETE)
+    BDSM_dbg("GSSAPI: Imported name\n");
+  else
+  {
+    BDSM_dbg("GSSAPI: Unable to import name\n");
+    return (0);
+  }
+
+  s->gss.credentials = GSS_C_NO_CREDENTIAL;
+  major_status = gss_acquire_cred_with_password(&minor_status,
+                                                gss_user,
+                                                &pass_buf, 0,
+                                                mechsp, GSS_C_ACCEPT,
+                                                &s->gss.credentials,
+                                                NULL, NULL);
+  if (major_status == GSS_S_COMPLETE)
+    BDSM_dbg("GSSAPI: Acquired credentials\n");
+  else
+  {
+    BDSM_dbg("GSSAPI: Unable to acquire credentials: 0x%x, 0x%x\n",
+             major_status, minor_status);
+    return (0);
+  }
+
+  return(1);
+}

+ 41 - 8
src/smb_session.c

@@ -24,6 +24,7 @@
 #include "bdsm/debug.h"
 #include "bdsm/debug.h"
 #include "bdsm/smb_session.h"
 #include "bdsm/smb_session.h"
 #include "bdsm/smb_ntlm.h"
 #include "bdsm/smb_ntlm.h"
+#include "bdsm/smb_gss.h"
 #include "bdsm/smb_transport.h"
 #include "bdsm/smb_transport.h"
 
 
 static int        smb_negotiate(smb_session *s);
 static int        smb_negotiate(smb_session *s);
@@ -36,9 +37,13 @@ smb_session   *smb_session_new()
   assert(s != NULL);
   assert(s != NULL);
   memset((void *)s, 0, sizeof(smb_session));
   memset((void *)s, 0, sizeof(smb_session));
 
 
+  // Explicitly sets pointer to NULL, insted of 0
+  s->gss.spnego.value   = NULL;
   s->transport.session  = NULL;
   s->transport.session  = NULL;
   s->shares             = NULL;
   s->shares             = NULL;
 
 
+  s->gss.ctx = GSS_C_NO_CONTEXT;
+
   return (s);
   return (s);
 }
 }
 
 
@@ -52,6 +57,10 @@ void            smb_session_destroy(smb_session *s)
       s->transport.destroy(s->transport.session);
       s->transport.destroy(s->transport.session);
       s->transport.session = NULL;
       s->transport.session = NULL;
     }
     }
+
+    if (s->gss.spnego.value != NULL)
+      free(s->gss.spnego.value);
+
     free(s);
     free(s);
   }
   }
 }
 }
@@ -150,7 +159,8 @@ static int        smb_negotiate(smb_session *s)
   const char          *dialects[] = SMB_DIALECTS;
   const char          *dialects[] = SMB_DIALECTS;
   smb_message         *msg = NULL;
   smb_message         *msg = NULL;
   smb_message         answer;
   smb_message         answer;
-  smb_negotiate_resp  *nego;
+  smb_nego_resp       *nego;
+  smb_nego_xsec_resp  *nego_xsec;
 
 
 
 
   msg = smb_message_new(SMB_CMD_NEGOTIATE, 128);
   msg = smb_message_new(SMB_CMD_NEGOTIATE, 128);
@@ -173,9 +183,8 @@ static int        smb_negotiate(smb_session *s)
   if (!smb_session_recv_msg(s, &answer))
   if (!smb_session_recv_msg(s, &answer))
     goto error;
     goto error;
 
 
-  nego = (smb_negotiate_resp *)answer.packet->payload;
-  if (answer.packet->header.status != NT_STATUS_SUCCESS
-      && nego->wct != 0x11 && nego->security_mode & 0x03)
+  nego = (smb_nego_resp *)answer.packet->payload;
+  if (answer.packet->header.status != NT_STATUS_SUCCESS && nego->wct != 0x11)
     goto error;
     goto error;
 
 
   s->srv.dialect        = nego->dialect_index;
   s->srv.dialect        = nego->dialect_index;
@@ -185,6 +194,18 @@ static int        smb_negotiate(smb_session *s)
   s->srv.challenge      = nego->challenge;
   s->srv.challenge      = nego->challenge;
   s->srv.ts             = nego->ts;
   s->srv.ts             = nego->ts;
 
 
+  // Copy SPNEGO supported mechanisms  token for later usage (login_gss())
+  if (smb_session_supports(s, SMB_SESSION_XSEC))
+  {
+    BDSM_dbg("Server is supporting extended security\n");
+
+    nego_xsec             = (smb_nego_xsec_resp *)nego;
+    s->gss.spnego.length  = nego_xsec->bct - 16;
+    s->gss.spnego.value   = malloc(s->gss.spnego.length);
+
+    assert(s->gss.spnego.value != NULL);
+    memcpy(s->gss.spnego.value, nego_xsec->gssapi, s->gss.spnego.length);
+  }
   // Yeah !
   // Yeah !
   s->state              = SMB_STATE_DIALECT_OK;
   s->state              = SMB_STATE_DIALECT_OK;
 
 
@@ -195,8 +216,8 @@ static int        smb_negotiate(smb_session *s)
     return (0);
     return (0);
 }
 }
 
 
-int             smb_session_login(smb_session *s, const char *domain,
-                                  const char *user, const char *password)
+static int        smb_session_login_ntlm(smb_session *s, const char *domain,
+                                         const char *user, const char *password)
 {
 {
   smb_message         answer;
   smb_message         answer;
   smb_message         *msg = NULL;
   smb_message         *msg = NULL;
@@ -285,6 +306,18 @@ int             smb_session_login(smb_session *s, const char *domain,
   return (1);
   return (1);
 }
 }
 
 
+int             smb_session_login(smb_session *s, const char *domain,
+                                  const char *user, const char *password)
+{
+  assert(s != NULL && user != NULL && password != NULL);
+
+  if (smb_session_supports(s, SMB_SESSION_XSEC))
+    return(smb_session_login_gss(s, domain, user, password));
+  else
+    return(smb_session_login_ntlm(s, domain, user, password));
+}
+
+
 int             smb_session_is_guest(smb_session *s)
 int             smb_session_is_guest(smb_session *s)
 {
 {
   // Invalid session object
   // Invalid session object
@@ -318,8 +351,8 @@ int             smb_session_supports(smb_session *s, int what)
 
 
   switch (what)
   switch (what)
   {
   {
-    case SMB_SESSION_EXT_SEC:
-      return (s->srv.caps & SMB_CAPS_EXT_SEC);
+    case SMB_SESSION_XSEC:
+      return (s->srv.caps & SMB_CAPS_XSEC);
     default:
     default:
       return (0);
       return (0);
   }
   }