Forráskód Böngészése

Refactor smb_session interaction with netbios session. It's now more generic and will allow to switch for directTcp

Julien 'Lta' BALLET 11 éve
szülő
commit
55e8069773

+ 6 - 3
Makefile.am

@@ -34,8 +34,10 @@ bdsm_HEADERS = \
     include/bdsm/smb_types.h    \
     include/bdsm/smb_utils.h
 noinst_HEADERS = \
-    include/bdsm/smb_packets.h  \
-    contrib/mdx/md4.h           \
+    include/bdsm/smb_packets.h    \
+    include/bdsm/smb_transport.h  \
+    include/bdsm/tcp_session.h    \
+    contrib/mdx/md4.h             \
     contrib/mdx/md5.h
 
 lib_LTLIBRARIES = libdsm.la
@@ -56,7 +58,8 @@ libdsm_la_SOURCES = \
     src/smb_session.c   \
     src/smb_share.c   \
     src/smb_stat.c    \
-    src/smb_trans2.c  \
+    src/smb_trans2.c      \
+    src/smb_transport.c   \
     src/smb_utils.c
 
 pkgconfigdir = $(libdir)/pkgconfig

+ 1 - 1
bin/dsm.c

@@ -127,7 +127,7 @@ int main(int ac, char **av)
 
   session = smb_session_new();
 
-  if (smb_session_connect(session, host, addr.sin_addr.s_addr))
+  if (smb_session_connect(session, host, addr.sin_addr.s_addr, SMB_TRANSPORT_NBT))
   {
     printf("Successfully connected to %s\n", host);
     fprintf(stderr, "Session key is 0x%x\n", session->srv.session_key);

+ 7 - 13
include/bdsm/netbios_session.h

@@ -33,10 +33,6 @@
 #define NETBIOS_SESSION_ERROR       -1
 #define NETBIOS_SESSION_REFUSED     -2
 
-#define NETBIOS_SESSION_BUFFER      8192
-#define NETBIOS_SESSION_PAYLOAD     NETBIOS_SESSION_BUFFER
-
-
 typedef struct              netbios_session_s {
   // The address of the remote peer;
   struct sockaddr_in          remote_addr;
@@ -48,23 +44,21 @@ typedef struct              netbios_session_s {
   size_t                      packet_payload_size;
   // Where is the write cursor relative to the beginning of the payload
   size_t                      packet_cursor;
-  // Our allocated packet, this is where the magic happen :)
+  // Our allocated packet, this is where the magic happen (both send and recv :)
   netbios_session_packet      *packet;
-  // Some buffer space to receive message from peer;
-  uint8_t                     recv_buffer[NETBIOS_SESSION_BUFFER];
 }                           netbios_session;
 
+
 // Return NULL if unable to open socket/connect
-netbios_session   *netbios_session_new(uint32_t ip_addr);
+netbios_session   *netbios_session_new(size_t buf_size);
 void              netbios_session_destroy(netbios_session *);
-
-int               netbios_session_connect(netbios_session *s,
+int               netbios_session_connect(struct in_addr *addr,
+                                          netbios_session *s,
                                           const char *name);
-void              netbios_session_packet_init(netbios_session *s,
-                                              uint8_t opcode);
+void              netbios_session_packet_init(netbios_session *s);
 int               netbios_session_packet_append(netbios_session *s,
                                                 const char *data, size_t size);
 int               netbios_session_packet_send(netbios_session *s);
-ssize_t           netbios_session_packet_recv(netbios_session *s);
+ssize_t           netbios_session_packet_recv(netbios_session *s, void **data);
 
 #endif

+ 9 - 0
include/bdsm/smb_defs.h

@@ -26,6 +26,15 @@
 
 #include <bdsm/smb_packets.h>
 
+#define SMB_IO_BUFSIZE    8192
+
+enum
+{
+  /// SMB with Direct-TCP connection (OSX supports only this)
+  SMB_TRANSPORT_TCP       = 1,
+  /// SMB with Netbios over TCP (older mechanism)
+  SMB_TRANSPORT_NBT       = 2
+};
 
 //-----------------------------------------------------------------------------/
 // SMB Session states

+ 3 - 4
include/bdsm/smb_session.h

@@ -63,7 +63,7 @@
  * call smb_session_connect, then authenticate with smb_authenticate.
  * @return A new Session object.
  */
-smb_session   *smb_session_new();
+smb_session     *smb_session_new();
 
 /**
  * @brief Close a session and deallocate its ressources
@@ -87,11 +87,10 @@ int             smb_session_state(smb_session *s);
 
 // ---------------------------------
 // Internal stuff, maybe move this somewhere else
-int             smb_negotiate(smb_session *s);
 int             smb_session_send_msg(smb_session *s, smb_message *msg);
 // msg->packet will be updated to point on received data. You don't own this
 // memory. It'll be reused on next recv_msg
-size_t          smb_session_recv_msg(smb_session *s, smb_message *msg);
+ssize_t         smb_session_recv_msg(smb_session *s, smb_message *msg);
 // --------------------------------
 
 /**
@@ -107,7 +106,7 @@ size_t          smb_session_recv_msg(smb_session *s, smb_message *msg);
  * @return 0 in case of error, a value > 0 otherwise.
  */
 int             smb_session_connect(smb_session *s, const char *name,
-                                    uint32_t ip);
+                                    uint32_t ip, int transport);
 
 /**
  * @brief Authenticate on the remote host with the provided credentials

+ 37 - 0
include/bdsm/smb_transport.h

@@ -0,0 +1,37 @@
+//---------------------------------------------------------------------------
+//  __________________    _________  _____            _____  .__         ._.
+//  \______   \______ \  /   _____/ /     \          /  _  \ |__| ____   | |
+//   |    |  _/|    |  \ \_____  \ /  \ /  \        /  /_\  \|  _/ __ \  | |
+//   |    |   \|    `   \/        /    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_TRANSPORT_H_
+#define __BDSM_SMB_TRANSPORT_H_
+
+#include "bdsm/smb_types.h"
+
+/**
+ * @internal
+ * @brief Fill the smb_transport structure with the fun pointers for using
+ * NBT transport
+ */
+void              smb_transport_nbt(smb_transport *tr);
+/**
+ * @internal
+ * @brief Fill the smb_transport structure with the fun pointers for using
+ * DirectTCP transport
+ */
+void              smb_transport_tcp(smb_transport *tr);
+
+#endif

+ 18 - 2
include/bdsm/smb_types.h

@@ -24,6 +24,11 @@
 #ifndef __BDSM_SMB_TYPES_H_
 #define __BDSM_SMB_TYPES_H_
 
+#include <netinet/ip.h>
+#include <stddef.h>
+
+#include "bdsm/smb_packets.h"
+
 /**
   * @struct smb_tid
   * @brief The id of a connection to a share within a session.
@@ -77,6 +82,17 @@ typedef struct smb_share_s
   uint16_t            guest_rights;
 } smb_share;
 
+typedef struct smb_transport_s {
+  void              *session;
+  void              *(*new)(size_t buf_size);
+  int               (*connect)(struct in_addr *addr, void *s, const char *name);
+  void              (*destroy)(void *s);
+  void              (*pkt_init)(void *s);
+  int               (*pkt_append)(void *s, void *data, size_t size);
+  int               (*send)(void *s);
+  ssize_t           (*recv)(void *s, void **data);
+}                   smb_transport;
+
 /**
  * @brief An opaque data structure to represent a SMB Session.
  */
@@ -85,7 +101,6 @@ typedef struct
   int                 state;
   int                 guest;            // boolean, are we logged as guest ?
   uint16_t            uid;              // uid attributed by the server
-  netbios_session   *nb_session;
 
   // Informations about the smb server we are connected to.
   struct {
@@ -98,6 +113,7 @@ typedef struct
     uint64_t            ts;             // It seems Win7 requires it :-/
   }                   srv;
 
+  smb_transport       transport;
   struct smb_share_s  *shares;          // shares->files | Map fd <-> smb_file
 }                   smb_session;
 
@@ -128,7 +144,7 @@ typedef struct
 {
   size_t          payload_size; // Size of the allocated payload
   size_t          cursor;       // Write cursor in the payload
-  smb_packet    *packet;      // Yummy yummy, Fruity fruity !
+  smb_packet      *packet;      // Yummy yummy, Fruity fruity !
 }                               smb_message;
 
 

+ 0 - 0
include/bdsm/tcp_session.h


+ 48 - 34
src/netbios_session.c

@@ -26,6 +26,7 @@
 #include <sys/socket.h>
 #include <unistd.h>
 
+#include "bdsm/debug.h"
 #include "bdsm/netbios_session.h"
 #include "bdsm/netbios_utils.h"
 
@@ -43,28 +44,19 @@ static int        open_socket_and_connect(netbios_session *s)
     return (0);
 }
 
-netbios_session *netbios_session_new(uint32_t ip_addr)
+netbios_session *netbios_session_new(size_t buf_size)
 {
-  netbios_session *session;
+  netbios_session   *session;
   size_t            packet_size;
 
   session = (netbios_session *)malloc(sizeof(netbios_session));
-  assert(session);
+  assert(session != NULL);
   memset((void *) session, 0, sizeof(netbios_session));
 
-  session->packet_payload_size = NETBIOS_SESSION_PAYLOAD;
+  session->packet_payload_size = buf_size;
   packet_size = sizeof(netbios_session_packet) + session->packet_payload_size;
   session->packet = (netbios_session_packet *)malloc(packet_size);
-  assert(session->packet);
-
-  session->remote_addr.sin_family       = AF_INET;
-  session->remote_addr.sin_port         = htons(NETBIOS_PORT_SESSION);
-  session->remote_addr.sin_addr.s_addr  = ip_addr;
-  if (!open_socket_and_connect(session))
-  {
-    netbios_session_destroy(session);
-    return (NULL);
-  }
+  assert(session->packet != NULL);
 
   return(session);
 }
@@ -79,17 +71,24 @@ void              netbios_session_destroy(netbios_session *s)
   free(s);
 }
 
-int               netbios_session_connect(netbios_session *s,
+int               netbios_session_connect(struct in_addr *addr,
+                                          netbios_session *s,
                                           const char *name)
 {
-  netbios_session_packet  *received;
   ssize_t                   recv_size;
   char                      *encoded_name;
 
-  assert(s && s->packet && s->socket);
+  assert(s != NULL && s->packet != NULL);
+
+  s->remote_addr.sin_family       = AF_INET;
+  s->remote_addr.sin_port         = htons(NETBIOS_PORT_SESSION);
+  s->remote_addr.sin_addr.s_addr  = addr->s_addr;
+  if (!open_socket_and_connect(s))
+    goto error;
 
   // Send the Session Request message
-  netbios_session_packet_init(s, NETBIOS_OP_SESSION_REQ);
+  netbios_session_packet_init(s);
+  s->packet->opcode = NETBIOS_OP_SESSION_REQ;
   encoded_name = netbios_name_encode(name, 0, NETBIOS_FILESERVER);
   netbios_session_packet_append(s, encoded_name, strlen(encoded_name) + 1);
   free(encoded_name);
@@ -102,13 +101,12 @@ int               netbios_session_connect(netbios_session *s,
     goto error;
 
   // Now receiving the reply from the server.
-  recv_size = netbios_session_packet_recv(s);
-  if (recv_size < sizeof(netbios_session_packet))
+  recv_size = netbios_session_packet_recv(s, NULL);
+  if (recv_size < 0)
     goto error;
 
-  received = (netbios_session_packet *)&s->recv_buffer;
   // Reply was negative, we are not connected :(
-  if (received->opcode != NETBIOS_OP_SESSION_REQ_OK)
+  if (s->packet->opcode != NETBIOS_OP_SESSION_REQ_OK)
   {
     s->state = NETBIOS_SESSION_REFUSED;
     return (0);
@@ -123,18 +121,12 @@ int               netbios_session_connect(netbios_session *s,
     return (0);
 }
 
-void              netbios_session_packet_init(netbios_session *s,
-                                              uint8_t opcode)
+void              netbios_session_packet_init(netbios_session *s)
 {
-  size_t          packet_size;
-
-  assert(s);
-
-  packet_size = s->packet_payload_size + sizeof(netbios_session_packet);
-  memset((void *)s->packet, 0, packet_size);
+  assert(s != NULL);
 
   s->packet_cursor = 0;
-  s->packet->opcode = opcode;
+  s->packet->opcode = NETBIOS_OP_SESSION_MSG;
 }
 
 int               netbios_session_packet_append(netbios_session *s,
@@ -174,10 +166,32 @@ int               netbios_session_packet_send(netbios_session *s)
   return (sent);
 }
 
-ssize_t           netbios_session_packet_recv(netbios_session *s)
+ssize_t           netbios_session_packet_recv(netbios_session *s, void **data)
 {
-  assert(s && s->socket && s->state > 0);
+  ssize_t         recv_size;
+  size_t          len;
+
+  assert(s != NULL && s->packet != NULL && s->socket && s->state > 0);
+
+  recv_size = recv(s->socket, (void *)(s->packet), s->packet_payload_size, 0);
+
+  if (recv_size < 0)
+    perror("netbios_session_packet_recv: ");
+
+  if (recv_size >= sizeof(netbios_session_packet) && data != NULL)
+    *data = (void *)s->packet->payload;
+  else if (data != NULL)
+    *data = NULL;
+
+  len  = ntohs(s->packet->length);
+  len |= (s->packet->flags & 0x01) << 16;
+
+  if (len != recv_size - sizeof(netbios_session_packet))
+  {
+    BDSM_dbg("netbios_session_packet_recv: Packet size mismatch\n");
+    return(-1);
+  }
 
-  return (recv(s->socket, (void *)&(s->recv_buffer), NETBIOS_SESSION_BUFFER, 0));
+  return (len);
 }
 

+ 1 - 1
src/smb_file.c

@@ -148,7 +148,7 @@ ssize_t   smb_fread(smb_session *s, smb_fd fd, void *buf, size_t buf_size)
   smb_message_set_andx_members(req_msg);
   smb_message_advance(req_msg, sizeof(smb_read_req));
 
-  max_read = NETBIOS_SESSION_BUFFER - 256; // XXX
+  max_read = SMB_IO_BUFSIZE - 256; // XXX
   max_read = max_read < buf_size ? max_read : buf_size;
 
   req = (smb_read_req *)req_msg->packet->payload;

+ 47 - 35
src/smb_session.c

@@ -24,6 +24,9 @@
 #include "bdsm/debug.h"
 #include "bdsm/smb_session.h"
 #include "bdsm/smb_ntlm.h"
+#include "bdsm/smb_transport.h"
+
+static int        smb_negotiate(smb_session *s);
 
 smb_session   *smb_session_new()
 {
@@ -33,6 +36,9 @@ smb_session   *smb_session_new()
   assert(s != NULL);
   memset((void *)s, 0, sizeof(smb_session));
 
+  s->transport.session  = NULL;
+  s->shares             = NULL;
+
   return (s);
 }
 
@@ -41,8 +47,11 @@ void            smb_session_destroy(smb_session *s)
   if (s != NULL)
   {
     // FIXME Free smb_share and smb_file
-    if (s->nb_session != NULL)
-      netbios_session_destroy(s->nb_session);
+    if (s->transport.session != NULL)
+    {
+      s->transport.destroy(s->transport.session);
+      s->transport.session = NULL;
+    }
     free(s);
   }
 }
@@ -56,13 +65,28 @@ int             smb_session_state(smb_session *s)
 }
 
 int             smb_session_connect(smb_session *s, const char *name,
-                                    uint32_t ip)
+                                    uint32_t ip, int transport)
 {
   assert(s != NULL && name != NULL);
 
-  if ((s->nb_session = netbios_session_new(ip)) == NULL)
+  if (s->transport.session != NULL)
+    s->transport.destroy(s->transport.session);
+
+  switch (transport)
+  {
+    case SMB_TRANSPORT_TCP:
+      smb_transport_tcp(&s->transport);
+      break;
+    case SMB_TRANSPORT_NBT:
+      smb_transport_nbt(&s->transport);
+      break;
+    default:
+      goto error;
+  }
+
+  if ((s->transport.session = s->transport.new(SMB_IO_BUFSIZE)) == NULL)
     goto error;
-  if (!netbios_session_connect(s->nb_session, name))
+  if (!s->transport.connect((struct in_addr *)&ip, s->transport.session, name))
     goto error;
 
   memcpy(s->srv.name, name, strlen(name) + 1);
@@ -80,50 +104,39 @@ int             smb_session_connect(smb_session *s, const char *name,
 
 int             smb_session_send_msg(smb_session *s, smb_message *msg)
 {
-  size_t        packet_size;
+  size_t        pkt_sz;
 
-  assert(s != NULL && s->state >= SMB_STATE_NETBIOS_OK && s->nb_session != NULL);
+  assert(s != NULL && s->state >= SMB_STATE_NETBIOS_OK);
+  assert(s->transport.session != NULL);
   assert(msg != NULL && msg->packet != NULL);
 
   msg->packet->header.uid = s->uid;
 
-  netbios_session_packet_init(s->nb_session, NETBIOS_OP_SESSION_MSG);
+  s->transport.pkt_init(s->transport.session);
 
-  packet_size   = sizeof(smb_packet) + msg->cursor;
-  if (!netbios_session_packet_append(s->nb_session, (char *)msg->packet, packet_size))
+  pkt_sz = sizeof(smb_packet) + msg->cursor;
+  if (!s->transport.pkt_append(s->transport.session, (void *)msg->packet, pkt_sz))
     return (0);
-  if (!netbios_session_packet_send(s->nb_session))
+  if (!s->transport.send(s->transport.session))
     return (0);
 
   return (1);
 }
 
-size_t          smb_session_recv_msg(smb_session *s, smb_message *msg)
+ssize_t         smb_session_recv_msg(smb_session *s, smb_message *msg)
 {
-  netbios_session_packet  *nb_packet;
-  ssize_t                   recv_size;
-  size_t                    payload_size;
+  void                      *data;
+  ssize_t                   payload_size;
 
-  assert(s != NULL && s->nb_session != NULL);
+  assert(s != NULL && s->transport.session != NULL);
 
-  recv_size = netbios_session_packet_recv(s->nb_session);
-  if(recv_size <= 0)
+  payload_size = s->transport.recv(s->transport.session, &data);
+  if(payload_size <= 0)
     return (0);
 
-  nb_packet   = (netbios_session_packet *)s->nb_session->recv_buffer;
-  if (msg != NULL)
-    msg->packet = (smb_packet *)nb_packet->payload;
-
-  payload_size  = ntohs(nb_packet->length);
-  payload_size |= (nb_packet->flags & 0x01) << 16; // XXX If this is the case we overran our recv_buffer
-  if (payload_size > recv_size - sizeof(netbios_session_packet))
-  {
-    BDSM_dbg("smb_session_recv_msg: Packet size mismatch\n");
-    return(0);
-  }
-
   if (msg != NULL)
   {
+    msg->packet = (smb_packet *)data;
     msg->payload_size = payload_size - sizeof(smb_header);
     msg->cursor       = 0;
   }
@@ -132,9 +145,9 @@ size_t          smb_session_recv_msg(smb_session *s, smb_message *msg)
 }
 
 
-int             smb_negotiate(smb_session *s)
+static int        smb_negotiate(smb_session *s)
 {
-  const char            *dialects[] = SMB_DIALECTS;
+  const char          *dialects[] = SMB_DIALECTS;
   smb_message         *msg = NULL;
   smb_message         answer;
   smb_negotiate_resp  *nego;
@@ -200,9 +213,8 @@ int             smb_session_login(smb_session *s, const char *domain,
   req = (smb_session_req *)msg->packet->payload;
 
   req->wct              = (sizeof(smb_session_req) - 3) / 2;
-  req->max_buffer       = NETBIOS_SESSION_PAYLOAD
-                          - sizeof(smb_header)
-                          - sizeof(netbios_session_packet);
+  req->max_buffer       = SMB_IO_BUFSIZE
+                          - sizeof(smb_header);
   req->max_buffer      -= sizeof(netbios_session_packet);
   req->max_buffer      -= sizeof(smb_packet);
   req->mpx_count        = 16; // XXX ?

+ 1 - 1
src/smb_share.c

@@ -201,7 +201,7 @@ size_t          smb_share_get_list(smb_session *s, char ***list)
 
   memset((void *)trans, 0, sizeof(smb_trans_req));
 
-  rpc_len = NETBIOS_SESSION_PAYLOAD - 256; // XXX
+  rpc_len = SMB_IO_BUFSIZE - 256; // XXX
 
   trans->wct                    = 16;
   trans->total_data_count       = 72;

+ 40 - 0
src/smb_transport.c

@@ -0,0 +1,40 @@
+//---------------------------------------------------------------------------
+//  __________________    _________  _____            _____  .__         ._.
+//  \______   \______ \  /   _____/ /     \          /  _  \ |__| ____   | |
+//   |    |  _/|    |  \ \_____  \ /  \ /  \        /  /_\  \|  _/ __ \  | |
+//   |    |   \|    `   \/        /    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 <assert.h>
+
+#include "bdsm/smb_transport.h"
+#include "bdsm/netbios_session.h"
+
+void              smb_transport_nbt(smb_transport *tr)
+{
+  assert(tr != NULL);
+
+  tr->new           = netbios_session_new;
+  tr->connect       = netbios_session_connect;
+  tr->destroy       = netbios_session_destroy;
+  tr->pkt_init      = netbios_session_packet_init;
+  tr->pkt_append    = netbios_session_packet_append;
+  tr->send          = netbios_session_packet_send;
+  tr->recv          = netbios_session_packet_recv;
+}
+
+void              smb_transport_tcp(smb_transport *tr)
+{
+  assert(tr != NULL);
+}