浏览代码

Adds new utils (discover,inverse,lookup). Implements QueryPathInfo and FindFirst2 (to list folders)

* Also, fix a bug that would cause to send 4 extra bytes at the end of
  each smb message
Julien 'Lta' BALLET 11 年之前
父节点
当前提交
8dde0d562b
共有 19 个文件被更改,包括 775 次插入50 次删除
  1. 6 0
      .gitignore
  2. 39 15
      Makefile
  3. 2 2
      README.md
  4. 48 0
      discover.c
  5. 31 12
      dsm.c
  6. 23 0
      include/bdsm/smb_defs.h
  7. 116 1
      include/bdsm/smb_packets.h
  8. 6 6
      include/bdsm/smb_session.h
  9. 1 1
      include/bdsm/smb_share.h
  10. 28 0
      include/bdsm/smb_trans2.h
  11. 55 0
      inverse.c
  12. 56 0
      lookup.c
  13. 3 2
      src/netbios_ns.c
  14. 1 1
      src/netbios_session.c
  15. 1 0
      src/smb_file.c
  16. 10 5
      src/smb_message.c
  17. 1 2
      src/smb_session.c
  18. 121 3
      src/smb_share.c
  19. 227 0
      src/smb_trans2.c

+ 6 - 0
.gitignore

@@ -2,3 +2,9 @@ pysmb-1.1.8/*
 ref/*
 *.o
 dsm
+*.so
+*.a
+discover
+lookup
+inverse
+

+ 39 - 15
Makefile

@@ -18,39 +18,63 @@
 
 
 
-CFLAGS      = -g3 -Iinclude -DBDSM_DEBUG=1 -D_BSD_SOURCE -std=c99 #-Wall -Wextra
-LDFLAGS     = -lcrypto #-levent
-CC          = clang
+CFLAGS      	= -g3 -Iinclude -DBDSM_DEBUG=1 -D_BSD_SOURCE -std=c99 -fPIC
+LDFLAGS     	= -lcrypto #-levent
+CC          	= clang
+AR						= ar
+RANLIB				= ranlib
 
-UTIL				= dsm
-LIB					= libdsm.so
+LIB						= libdsm.so
+LIB_STATIC		= libdsm.a
+UTILS					= dsm discover inverse lookup
 
-UTIL_SRC		= dsm.c 							    \
-			src/netbios_utils.c				\
+LIB_SRC				= src/netbios_utils.c	\
 			src/netbios_ns.c				\
-			src/netbios_ns_entry.c				\
-			src/netbios_query.c				\
-			src/netbios_session.c				\
+			src/netbios_ns_entry.c	\
+			src/netbios_query.c			\
+			src/netbios_session.c		\
 			src/smb_utils.c					\
 			src/smb_message.c				\
 			src/smb_session.c				\
 			src/smb_ntlm.c					\
 			src/smb_share.c					\
 			src/smb_file.c					\
+			src/smb_trans2.c				\
 			src/context.c
+DSM_SRC				= dsm.c
+DISCOVER_SRC	= discover.c
+INVERSE_SRC		= inverse.c
+LOOKUP_SRC		= lookup.c
 
-UTIL_OBJS		= $(UTIL_SRC:.c=.o)
+LIB_LDFLAGS		= -shared
 
-all: $(UTIL)
+LIB_OBJS			= $(LIB_SRC:.c=.o)
+
+all: $(LIB) $(LIB_STATIC) $(UTILS)
 
 clean:
-	rm -f $(UTIL) $(UTIL_OBJS)
+	rm -f $(UTILS) $(LIB) $(LIB_STATIC)
+	rm -rf $(LIB_OBJS)
 
 re: clean all
 c: clean
 
-$(UTIL): $(UTIL_OBJS)
-	$(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(UTIL_OBJS)
+$(LIB): $(LIB_OBJS)
+	$(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(LIB_LDFLAGS) $(LIB_OBJS)
+$(LIB_STATIC): $(LIB_OBJS)
+	$(AR) -rcs $@ $(LIB_OBJS)
+
+
+test:
+
+dsm: $(LIB) $(DSM_SRC)
+	$(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(DSM_SRC) $(LIB_STATIC)
+discover: $(LIB) $(DISCOVER_SRC)
+	$(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(DISCOVER_SRC) $(LIB_STATIC)
+inverse: $(LIB) $(INVERSE_SRC)
+	$(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(INVERSE_SRC) $(LIB_STATIC)
+lookup:  $(LIB) $(LOOKUP_SRC)
+	$(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(LOOKUP_SRC) $(LIB_STATIC)
 
 .c.o:
 	$(CC) -c $(CFLAGS) -o $@ $<

+ 2 - 2
README.md

@@ -20,7 +20,7 @@ Here's a list of features i intend to support in this project :
 * SMB
   ** Support only required parts of 'NT LM 0.12' (aka CIFS?) dialect.
   ** User based authentication [Done]
-  ** List Shares
+  ** List Shares [Partial/Ugly]
   ** Browse folders
-  ** Read file
+  ** Read file [Done, can be improved :)]
   ** No write, lock, RPCs, etc.

+ 48 - 0
discover.c

@@ -0,0 +1,48 @@
+//---------------------------------------------------------------------------
+//  __________________    _________  _____            _____  .__         ._.
+//  \______   \______ \  /   _____/ /     \          /  _  \ |__| ____   | |
+//   |    |  _/|    |  \ \_____  \ /  \ /  \        /  /_\  \|  _/ __ \  | |
+//   |    |   \|    `   \/        /    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 <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "bdsm.h"
+
+int main(int ac, char **av)
+{
+  bdsm_context_t      *ctx;
+  netbios_ns_entry_t  *iter;
+
+  ctx = bdsm_context_new();
+  assert(ctx);
+
+  if (!netbios_ns_discover(ctx->ns))
+  {
+    fprintf(stderr, "Error while discovering local network\n");
+    exit(42);
+  }
+
+  iter = ctx->ns->entries;
+  while (iter != NULL)
+  {
+    printf("Found %s\n", iter->name);
+    iter = iter->next;
+  }
+
+  return (0);
+}

+ 31 - 12
dsm.c

@@ -35,6 +35,7 @@
 #define NBT_TCP_PORT        139
 
 #include "bdsm.h"
+#include "bdsm/smb_trans2.h"
 
 #include <openssl/md4.h>
 #include <openssl/md5.h>
@@ -108,7 +109,7 @@ int main(int ac, char **av)
   }
   fprintf(stderr, "Connected to IPC$ share\n");
 
-  smb_tid test = smb_tree_connect(session, "TEST");
+  smb_tid test = smb_tree_connect(session, "test");
   if (test)
     fprintf(stderr, "Connected to Test share\n");
   else
@@ -117,22 +118,23 @@ int main(int ac, char **av)
     exit(42);
   }
 
-  smb_fd fd = smb_fopen(session, test, "\\test.avi", SMB_MOD_RO);
-  if (fd)
-    fprintf(stderr, "Successfully opened \\test.avi: fd = 0x%.8x\n", fd);
-  else
-  {
-    fprintf(stderr, "Unable to open \\test.avi\n");
-    exit(42);
-  }
+  // smb_fd fd = smb_fopen(session, test, "\\BDSM\\test.txt", SMB_MOD_RO);
+  // if (fd)
+  //   fprintf(stderr, "Successfully opened file: fd = 0x%.8x\n", fd);
+  // else
+  // {
+  //   fprintf(stderr, "Unable to open file\n");
+  //   exit(42);
+  // }
 
   char              data[1024];
   smb_share_list_t  *share_list;
+  smb_file_t        *files;
 
 
-  smb_fread(session, fd, data, 1024);
-  fprintf(stderr, "Read from file:\n%s\n", data);
-  smb_fclose(session, fd);
+  // smb_fread(session, fd, data, 1024);
+  // fprintf(stderr, "Read from file:\n%s\n", data);
+  // smb_fclose(session, fd);
 
   if (!smb_share_list(session, &share_list))
   {
@@ -144,6 +146,23 @@ int main(int ac, char **av)
     fprintf(stderr, "Share list : \n");
   }
 
+  fprintf(stderr, "Let's find files at share's root :\n");
+  files = smb_find(session, test, "\\*");
+  if (files != NULL)
+    while(files)
+    {
+      fprintf(stderr, "Found a file %s \n", files->name);
+      files = files->next;
+    }
+  else
+    fprintf(stderr, "Unable to list files\n");
+
+  fprintf(stderr, "Query file info for path: %s\n", av[4]);
+  files = smb_stat(session, test, av[4]);
+
+  if (files)
+    printf("File %s is %d bytes long", av[4], files->size);
+
 
   smb_session_destroy(session);
   bdsm_context_destroy(ctx);

+ 23 - 0
include/bdsm/smb_defs.h

@@ -44,6 +44,9 @@
 #define SMB_CMD_READ            0x2e // Read AndX
 #define SMB_CMD_CREATE          0xa2 // NT Create AndX
 
+#define SMB_TR2_FIND_FIRST      0x0001
+#define SMB_TR2_QUERY_PATH      0x0005
+
 ///////////////////////////////////////////////////////////////////////////////
 //// Flags definitions
 
@@ -125,6 +128,26 @@
 #define SMB_SHARE_WRITE         (1 << 1)
 #define SMB_SHARE_DELETE        (1 << 2)
 
+// Trans 2 flags
+//// Find First 2
+#define SMB_FIND2_ATTR_RO       (1 << 0)  // Include RO files in result
+#define SMB_FIND2_ATTR_HIDDEN   (1 << 1)  // Include hidden files
+#define SMB_FIND2_ATTR_SYSTEM   (1 << 2)  // Include system files
+#define SMB_FIND2_ATTR_VOLUME   (1 << 3)  // Include volume ID ?
+#define SMB_FIND2_ATTR_DIR      (1 << 4)  // Include directory ?
+#define SMB_FIND2_ATTR_ARCHIVE  (1 << 5)  // Include archive ?
+#define SMB_FIND2_ATTR_DEFAULT  (SMB_FIND2_ATTR_RO | SMB_FIND2_ATTR_HIDDEN |  \
+                                 SMB_FIND2_ATTR_SYSTEM | SMB_FIND2_ATTR_DIR)
+
+#define SMB_FIND2_FLAG_CLOSE      (1 << 0)  // Close search after request ?
+#define SMB_FIND2_FLAG_CLOSE_EOS  (1 << 1)  // Close after End Of Search ?
+#define SMB_FIND2_FLAG_RESUME     (1 << 2)  // Send resume keys ?
+#define SMB_FIND2_FLAG_CONTINUE   (1 << 3)  // not set == new search
+#define SMB_FIND2_FLAG_BACKUP     (1 << 3)  // Backup intent ?
+#define SMB_FIND2_FLAG_DEFAULT    (SMB_FIND2_FLAG_CLOSE_EOS | \
+                                   SMB_FIND2_FLAG_RESUME)
+
+
 
 
 

+ 116 - 1
include/bdsm/smb_packets.h

@@ -252,7 +252,6 @@ typedef struct
   uint16_t      pipe_function;
   uint16_t      fid;
   uint16_t      bct;
-  uint8_t       padding;
   uint8_t       payload[];
 } __attribute__((packed))   smb_trans_req_t;
 
@@ -260,6 +259,122 @@ typedef struct
 
 
 
+//-> Trans2
+typedef struct
+{
+  uint8_t       wct;                // 15
+  uint16_t      total_param_count;
+  uint16_t      total_data_count;
+  uint16_t      max_param_count;
+  uint16_t      max_data_count;
+  uint8_t       max_setup_count;
+  uint8_t       reserved;
+  uint16_t      flags;
+  uint32_t      timeout;
+  uint16_t      reserve2;
+  uint16_t      param_count;
+  uint16_t      param_offset;
+  uint16_t      data_count;
+  uint16_t      data_offset;
+  uint8_t       setup_count;
+  uint8_t       reserved3;
+  uint16_t      cmd;
+  uint16_t      bct;
+  uint8_t       padding[3];
+  uint8_t       payload[];
+} __attribute__((packed))   smb_trans2_req_t;
+
+//// -> Trans2|FindFirst2
+typedef struct
+{
+  uint16_t      attrs;              // Search attributes
+  uint16_t      count;              // Search count
+  uint16_t      flags;
+  uint16_t      interest;           // What kind of info do we want ?
+  uint32_t      storage;            // ? => 0
+  uint8_t       pattern[];          // The queried pattern "\\folder\\*"
+} __attribute__((packed))   smb_tr2_find2_t;
+
+//// -> Trans2|QueryPathInfo
+typedef struct
+{
+  uint16_t      interest;
+  uint32_t      reserved;
+  uint8_t       path[];
+} __attribute__((packed))   smb_tr2_query_t;
+
+//<- Trans2
+
+typedef struct
+{
+  uint8_t       wct;                // 10
+  uint16_t      total_param_count;
+  uint16_t      total_data_count;
+  uint16_t      reserved;
+  uint16_t      param_count;
+  uint16_t      param_offset;
+  uint16_t      param_displacement; // ??
+  uint16_t      data_count;
+  uint16_t      data_offset;
+  uint16_t      data_displacement;  // ??
+  uint8_t       setup_count;
+  uint8_t       reserved2;
+  uint16_t      bct;
+  uint8_t       padding;
+  uint8_t       payload[];
+} __attribute__((packed))   smb_trans2_resp_t;
+
+//// <- Trans2|FindFirst2Params
+typedef struct
+{
+  uint16_t      id;
+  uint16_t      count;
+  uint16_t      eos;
+  uint16_t      ea_error_offset;
+  uint16_t      last_name_offset;
+  uint16_t      padding;
+} __attribute__((packed))   smb_tr2_find2_params_t;
+
+//// <- Trans2|FindFirst2FileInfo
+typedef struct
+{
+  uint32_t      next_entry;
+  uint32_t      index;
+  uint64_t      created;            // File creation time
+  uint64_t      accessed;           // File last access time
+  uint64_t      written;            // File last write time
+  uint64_t      changed;            // File last modification time
+  uint64_t      size;
+  uint64_t      alloc_size;
+  uint32_t      attr;
+  uint32_t      name_len;
+  uint32_t      ea_list_len;
+  uint8_t       short_name_len;
+  uint8_t       reserved;
+  uint8_t       short_name[24];
+  uint8_t       name[];
+} __attribute__((packed))   smb_tr2_find2_entry_t;
+
+
+//// <- Trans2|QueryPathInfo
+typedef struct
+{
+  uint64_t      created;
+  uint64_t      accessed;
+  uint64_t      written;
+  uint64_t      changed;
+  uint32_t      attr;
+  uint64_t      alloc_size;
+  uint64_t      size;
+  uint32_t      link_count;
+  uint8_t       rm_pending;
+  uint8_t       is_dir;
+  uint32_t      ea_list_len;
+  uint32_t      name_len;
+  uint8_t       name[];
+} __attribute__((packed))   smb_tr2_path_info_t;
+
+
 //-> Example
 typedef struct
 {

+ 6 - 6
include/bdsm/smb_session.h

@@ -45,11 +45,13 @@ typedef uint32_t    smb_fd;
 #define SMB_FD_FID(fd)    ((smb_fid)(fd & 0x0000ffff))
 #define SMB_FD(tid, fid)  ((((smb_fd)tid) << 16) | (((smb_fd) fid)))
 
-typedef struct smb_file_s
+typedef struct  smb_file_s
 {
-  smb_fid             fid;
   struct smb_file_s   *next;          // Next file in this share
+  char                *name;
+  smb_fid             fid;
   smb_tid             tid;
+  size_t              name_len;
   uint64_t            created;
   uint64_t            accessed;
   uint64_t            written;
@@ -63,12 +65,12 @@ typedef struct smb_file_s
 
 typedef struct smb_share_s
 {
-  smb_tid             tid;
   struct smb_share_s  *next;          // Next share in this session
+  struct smb_file_s   *files;         // List of all open files for this share
+  smb_tid             tid;
   uint16_t            opts;           // Optionnal support opts
   uint16_t            rights;         // Maximum rights field
   uint16_t            guest_rights;
-  struct smb_file_s   *files;         // List of all open files for this share
 } smb_share_t;
 
 typedef struct
@@ -99,7 +101,6 @@ smb_session_t   *smb_session_new();
 void            smb_session_destroy(smb_session_t *s);
 
 
-
 void            smb_session_share_add(smb_session_t *s, smb_share_t *share);
 smb_share_t     *smb_session_share_get(smb_session_t *s, smb_tid tid);
 smb_share_t     *smb_session_share_remove(smb_session_t *s, smb_tid tid);
@@ -109,7 +110,6 @@ smb_file_t      *smb_session_file_get(smb_session_t *s, smb_fd fd);
 smb_file_t      *smb_session_file_remove(smb_session_t *s, smb_fd fd);
 
 
-
 int             smb_session_send_msg(smb_session_t *s, smb_message_t *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

+ 1 - 1
include/bdsm/smb_share.h

@@ -24,7 +24,7 @@
 
 typedef struct  smb_share_list_s
 {
-  char                name[16];
+  char                name[32];
 }               smb_share_list_t;
 
 size_t          smb_share_list(smb_session_t *s, smb_share_list_t **list);

+ 28 - 0
include/bdsm/smb_trans2.h

@@ -0,0 +1,28 @@
+//---------------------------------------------------------------------------
+//  __________________    _________  _____            _____  .__         ._.
+//  \______   \______ \  /   _____/ /     \          /  _  \ |__| ____   | |
+//   |    |  _/|    |  \ \_____  \ /  \ /  \        /  /_\  \|  _/ __ \  | |
+//   |    |   \|    `   \/        /    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_TRANS2_H_
+#define __BDSM_SMB_TRANS2_H_
+
+#include "bdsm/smb_defs.h"
+#include "bdsm/smb_session.h"
+
+smb_file_t  *smb_find(smb_session_t *s, smb_tid tid, const char *pattern);
+smb_file_t  *smb_stat(smb_session_t *s, smb_tid tid, const char *path);
+
+#endif

+ 55 - 0
inverse.c

@@ -0,0 +1,55 @@
+//---------------------------------------------------------------------------
+//  __________________    _________  _____            _____  .__         ._.
+//  \______   \______ \  /   _____/ /     \          /  _  \ |__| ____   | |
+//   |    |  _/|    |  \ \_____  \ /  \ /  \        /  /_\  \|  _/ __ \  | |
+//   |    |   \|    `   \/        /    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 <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "bdsm.h"
+
+int main(int ac, char **av)
+{
+  bdsm_context_t      *ctx;
+  netbios_ns_entry_t  ns_entry;
+
+  ctx = bdsm_context_new();
+  assert(ctx);
+
+  if (ac != 2)
+  {
+    fprintf(stderr, "%s usage: %s a.b.c.d\n", av[0], av[0]);
+    fprintf(stderr, "Print the netbios name for this IP address\n");
+    exit(1);
+  }
+
+  inet_aton(av[1], &ns_entry.address);
+  if (!netbios_ns_inverse(ctx->ns, &ns_entry))
+  {
+    fprintf(stderr, "Unable to perform inverse name resolution for %s\n", av[1]);
+    exit(42);
+  }
+
+  printf("%s\n", ns_entry.name);
+
+  return (0);
+}

+ 56 - 0
lookup.c

@@ -0,0 +1,56 @@
+//---------------------------------------------------------------------------
+//  __________________    _________  _____            _____  .__         ._.
+//  \______   \______ \  /   _____/ /     \          /  _  \ |__| ____   | |
+//   |    |  _/|    |  \ \_____  \ /  \ /  \        /  /_\  \|  _/ __ \  | |
+//   |    |   \|    `   \/        /    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 <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "bdsm.h"
+
+int main(int ac, char **av)
+{
+  bdsm_context_t      *ctx;
+  char                name[NETBIOS_NAME_LENGTH + 2];
+  struct in_addr      addr;
+
+  ctx = bdsm_context_new();
+  assert(ctx);
+
+  if (ac != 2)
+  {
+    fprintf(stderr, "%s usage: %s NBT_NAME\n", av[0], av[0]);
+    fprintf(stderr, "Print the ip for this netbios name\n");
+    exit(1);
+  }
+
+  addr.s_addr = netbios_ns_resolve(ctx->ns, av[1], NETBIOS_FILESERVER);
+  if (!addr.s_addr)
+  {
+    fprintf(stderr, "Unable to perform name resolution for %s\n", av[1]);
+    exit(42);
+  }
+
+  printf("%s's IP address is : %s\n", av[1], inet_ntoa(addr));
+
+  return (0);
+}

+ 3 - 2
src/netbios_ns.c

@@ -288,7 +288,7 @@ int           netbios_ns_discover(netbios_ns_t *ns)
     iter = iter->next;
   }
 
-  return (0);
+  return (1);
 }
 
 // Perform inverse name resolution. Grap an IP and return the first <20> field
@@ -347,7 +347,8 @@ int           netbios_ns_inverse(netbios_ns_t *ns, netbios_ns_entry_t *entry)
     current_name = names + name_idx * 18;
     if (current_name[15] == 0x20)
     {
-      printf("Found name : %s\n", current_name);
+      if (BDSM_DEBUG)
+        fprintf(stderr, "Found name : %s\n", current_name);
       memcpy(entry->name, current_name, NETBIOS_NAME_LENGTH + 2);
       return (1);
     }

+ 1 - 1
src/netbios_session.c

@@ -168,7 +168,7 @@ int               netbios_session_packet_send(netbios_session_t *s)
 
   if (sent != to_send)
   {
-    perror("netbios_session_packet_send: Unable to send (full) packet");
+    perror("netbios_session_packet_send: Unable to send (full?) packet");
     return (0);
   }
 

+ 1 - 0
src/smb_file.c

@@ -107,6 +107,7 @@ void        smb_fclose(smb_session_t *s, smb_fd fd)
 
   assert(s != NULL && fd);
 
+  // XXX Memory leak, destroy the file after removing it
   if ((file = smb_session_file_remove(s, fd)) == NULL)
     return;
 

+ 10 - 5
src/smb_message.c

@@ -31,13 +31,11 @@ smb_message_t   *smb_message_new(uint8_t cmd, size_t payload_size)
   const char    magic[4] = SMB_MAGIC;
   smb_message_t *msg;
 
-  msg = (smb_message_t *)malloc(sizeof(smb_message_t));
+  msg = (smb_message_t *)calloc(1, sizeof(smb_message_t));
   assert(msg != NULL);
-  memset((void *)msg, 0, sizeof(smb_message_t));
 
-  msg->packet = (smb_packet_t *)malloc(sizeof(smb_message_t) + payload_size);
+  msg->packet = (smb_packet_t *)calloc(1, sizeof(smb_message_t) + payload_size);
   assert(msg != NULL);
-  memset((void *)msg->packet, 0, sizeof(smb_message_t) + payload_size);
 
   msg->payload_size = payload_size;
   msg->cursor = 0;
@@ -71,6 +69,8 @@ int             smb_message_append(smb_message_t *msg, const void *data,
   memcpy(msg->packet->payload + msg->cursor, data, data_size);
   msg->cursor += data_size;
 
+  //fprintf(stderr, "Cursor is at %d (append)\n", msg->cursor);
+
   return (1);
 }
 
@@ -78,10 +78,12 @@ int             smb_message_advance(smb_message_t *msg, size_t size)
 {
   assert(msg != NULL);
 
-  if (msg->cursor + size > msg->payload_size)
+  if (msg->payload_size < msg->cursor + size)
     return (0);
 
   msg->cursor += size;
+
+  //fprintf(stderr, "Cursor is at %d (advance)\n", msg->cursor);
   return (1);
 }
 
@@ -116,6 +118,9 @@ size_t          smb_message_put_utf16(smb_message_t *msg, const char *src_enc,
   res = smb_message_append(msg, utf_str, utf_str_len);
   free(utf_str);
 
+  //fprintf(stderr, "put_utf16, adds %d bytes, cursor is at %d\n",
+  //        utf_str_len, msg->cursor);
+
   if (res)
     return(utf_str_len);
   return (0);

+ 1 - 2
src/smb_session.c

@@ -74,8 +74,7 @@ int             smb_session_send_msg(smb_session_t *s, smb_message_t *msg)
 
   netbios_session_packet_init(s->nb_session, NETBIOS_OP_SESSION_MSG);
 
-  packet_size   = sizeof(netbios_session_packet_t) + sizeof(smb_packet_t);
-  packet_size  += msg->cursor;
+  packet_size   = sizeof(smb_packet_t) + msg->cursor;
   if (!netbios_session_packet_append(s->nb_session, (char *)msg->packet, packet_size))
     return (0);
   if (!netbios_session_packet_send(s->nb_session))

+ 121 - 3
src/smb_share.c

@@ -96,6 +96,49 @@ int           smb_tree_disconnect(smb_session_t *s, smb_tid tid)
   return (0);
 }
 
+// Here we parse the NetShareEnumAll response packet payload to extract
+// The share list.
+// We are assuming share name are limited to 16 characters
+static size_t   smb_share_parse_enum(smb_message_t *msg,
+                                     smb_share_list_t **list)
+{
+  uint32_t          share_count, i;
+  uint8_t           *data, *eod;
+  smb_share_list_t  *s;
+
+  assert(msg != NULL && list != NULL);
+  // Let's skip smb parameters, DCE/RPC stuff until we are at the begginning of
+  // NetShareCtrl
+
+  share_count = *((uint32_t *)(msg->packet->payload + 60));
+  data        = msg->packet->payload + 72 + share_count * 12;
+  eod         = msg->packet->payload + msg->payload_size;
+
+  s = calloc(share_count, sizeof(smb_share_list_t));
+  assert (s != NULL);
+
+  for (i = 0; i < share_count && data < eod; i++)
+  {
+    uint32_t name_len, com_len;
+
+
+    name_len = *((uint32_t *)data);   // Read 'Max Count', make it a multiple of 2
+    data    += 3 * sizeof(uint32_t);  // Move pointer to beginning of Name.
+    memcpy(s[i].name, data, name_len * 2); // Those are unicode strings.
+    if (name_len % 2) name_len += 1;  // Align next move
+    data    += name_len * 2;          // Move the pointer to Comment 'Max count'
+
+    com_len  = *((uint32_t *)data);
+    data    += 3 * sizeof(uint32_t);  // Move pointer to beginning of Comment.
+    if (com_len % 2) com_len += 1;    // Align next move
+    data    += com_len * 2;           // Move the pointer to next item
+  }
+
+  *list = s;
+
+  return (i);
+}
+
 // We should normally implement SCERPC and SRVSVC to perform a share list. But
 // since these two protocols have no other use for use, we'll do it the trash
 // way
@@ -145,8 +188,9 @@ size_t          smb_share_list(smb_session_t *s, smb_share_list_t **list)
   trans->fid                    = SMB_FD_FID(srvscv_fd);
   trans->bct                    = 89;
 
+  smb_message_put8(req, 0);   // Padding
   smb_message_put_utf16(req, "", "\\PIPE\\", strlen("\\PIPE\\") + 1);
-  smb_message_put16(req, 0); // Padding to be aligned with wtf boundary :-/
+  smb_message_put16(req, 0);  // Padding to be aligned with wtf boundary :-/
 
   // Now we'll 'build' the DCE/RPC Packet. This basically a copycat
   // from wireshark values.
@@ -194,7 +238,7 @@ size_t          smb_share_list(smb_session_t *s, smb_share_list_t **list)
 
 
   //// Phase 2:
-  // Now we have the 'bind' (regarless of what it is), we'll call
+  // Now we have the 'bind' done (regarless of what it is), we'll call
   // NetShareEnumAll
 
   req = smb_message_new(SMD_CMD_TRANS, 256);
@@ -206,6 +250,80 @@ size_t          smb_share_list(smb_session_t *s, smb_share_list_t **list)
 
   memset((void *)trans, 0, sizeof(smb_trans_req_t));
 
+  trans->wct              = 16;
+  trans->max_data_count   = 4280;
+  trans->setup_count      = 2;
+  trans->pipe_function    = 0x26; // TransactNmPipe;
+  trans->fid              = SMB_FD_FID(srvscv_fd);
+
+  smb_message_put8(req, 0);  // Padding
+  smb_message_put_utf16(req, "", "\\PIPE\\", strlen("\\PIPE\\") + 1);
+  smb_message_put16(req, 0); // Padding
+
+  // Now we'll 'build' the DCE/RPC Packet. This basically a copycat
+  // from wireshark values.
+  smb_message_put8(req, 5);     // version major
+  smb_message_put8(req, 0);     // minor
+  smb_message_put8(req, 0);     // Packet type = 'request'
+  smb_message_put8(req, 0x03);  // Packet flags = ??
+  smb_message_put32(req, 0x10); // Representation = little endian/ASCII. Damn
+  smb_message_put16(req, 88);   // Data len again
+  smb_message_put16(req, 0);    // Auth len ?
+  smb_message_put32(req, 20);   // Call ID ?
+  smb_message_put32(req, 64);   // Alloc hint ?
+  smb_message_put16(req, 0);    // Context ID ?
+  smb_message_put16(req, 15);   // OpNum = NetShareEnumAll
+
+  // Pointer to server UNC
+  smb_message_put32(req, 0x00020000);   // Referent ID ?
+  smb_message_put32(req, 8);            // Max count
+  smb_message_put32(req, 0);            // Offset
+  smb_message_put32(req, 8);            // Actual count
+    // The server name, supposed to be downcased
+  smb_message_put_utf16(req, "", s->srv.name, strlen(s->srv.name) + 1);
+  if ((strlen(s->srv.name) % 2) == 0) // It won't be aligned with the terminating byte
+  smb_message_put16(req, 0);
+
+
+  smb_message_put32(req, 1);            // Level 1 ?
+  smb_message_put32(req, 1);            // Ctr ?
+  smb_message_put32(req, 0x00020004);   // Referent ID ?
+  smb_message_put64(req, 0);            // Count/Null Pointer to NetShareInfo1
+  smb_message_put32(req, rpc_len);      // Max Buffer
+
+  smb_message_put32(req, 0x00020008);   // Referent ID ?
+  smb_message_put32(req, 0);            // Resume ?
+
+  // Sets length values
+  trans->bct              = req->cursor - sizeof(smb_trans_req_t);
+  trans->data_count       = trans->bct - 17; // 17 -> padding + \PIPE\ + padding
+  trans->total_data_count = trans->data_count;
+  trans->data_offset      = trans->data_count - 4;
+  trans->param_offset     = trans->data_count - 4;
+
+
+  // Let's send this ugly pile of shit over the network !
+  res = smb_session_send_msg(s, req);
+  smb_message_destroy(req);
+  if (!res)
+    return (0);
+
+  // Is the server throwing pile of shit back at me ?
+  res = smb_session_recv_msg(s, &resp);
+  if (!res && (uint32_t)resp.packet->payload[resp.payload_size - 4])
+  {
+    if (BDSM_DEBUG)
+      fprintf(stderr, "NetShareEnumAll call failed.\n");
+    return (0);
+  }
+
+
+  //// Phase 3
+  // We parse the list of Share (finally !) and build function response
+  res = smb_share_parse_enum(&resp, list);
+
+  // Close the pipe
+  smb_fclose(s, srvscv_fd);
 
-  return (1);
+  return (res);
 }

+ 227 - 0
src/smb_trans2.c

@@ -0,0 +1,227 @@
+//---------------------------------------------------------------------------
+//  __________________    _________  _____            _____  .__         ._.
+//  \______   \______ \  /   _____/ /     \          /  _  \ |__| ____   | |
+//   |    |  _/|    |  \ \_____  \ /  \ /  \        /  /_\  \|  _/ __ \  | |
+//   |    |   \|    `   \/        /    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/smb_trans2.h"
+
+static smb_file_t *smb_find_parse(smb_message_t *msg)
+{
+  smb_trans2_resp_t       *tr2;
+  smb_tr2_find2_params_t  *params;
+  smb_tr2_find2_entry_t   *iter;
+  smb_file_t              *files, *tmp;
+  uint8_t                 *eod;
+  size_t                  count, i;
+
+  assert(msg != NULL);
+
+  // Let's parse the answer we got from server
+  tr2     = (smb_trans2_resp_t *)msg->packet->payload;
+  params  = (smb_tr2_find2_params_t *)tr2->payload;
+  iter    = (smb_tr2_find2_entry_t *)(tr2->payload + sizeof(smb_tr2_find2_params_t));
+  eod     = msg->packet->payload + msg->payload_size;
+  count   = params->count;
+  files   = tmp = NULL;
+
+  for(i = 0; i < count && (uint8_t *)iter < eod; i++)
+  {
+    tmp = calloc(1, sizeof(smb_file_t));
+    assert(tmp != NULL);
+
+    tmp->name_len = iter->name_len + 2;
+    tmp->name     = malloc(tmp->name_len);
+    assert(tmp->name != NULL);
+    memcpy(tmp->name, iter->name, tmp->name_len - 2);
+    tmp->name[tmp->name_len - 1] = tmp->name[tmp->name_len - 2] = 0;
+
+    tmp->created    = iter->created;
+    tmp->accessed   = iter->accessed;
+    tmp->written    = iter->written;
+    tmp->changed    = iter->changed;
+    tmp->size       = iter->size;
+    tmp->alloc_size = iter->alloc_size;
+    tmp->attr       = iter->attr;
+    tmp->is_dir     = tmp->attr & SMB_ATTR_DIR;
+
+    tmp->next = files;
+    files     = tmp;
+
+    iter = (smb_tr2_find2_entry_t *)(((char *)iter) + iter->next_entry);
+  }
+
+  return (files);
+}
+
+smb_file_t  *smb_find(smb_session_t *s, smb_tid tid, const char *pattern)
+{
+  smb_message_t           *msg, reply;
+  smb_trans2_req_t        *tr2;
+  smb_tr2_find2_t         *find;
+  size_t                  pattern_len, msg_len;
+  int                     res;
+
+  assert(s != NULL && pattern != NULL && tid);
+
+  pattern_len = strlen(pattern) + 1;
+  msg_len     = sizeof(smb_trans2_req_t) + sizeof(smb_tr2_find2_t);
+  msg_len    += pattern_len * 2 + 3;
+
+  msg = smb_message_new(SMB_CMD_TRANS2, msg_len);
+  smb_message_set_default_flags(msg);
+  msg->packet->header.tid = tid;
+
+  tr2 = (smb_trans2_req_t *)msg->packet->payload;
+  tr2->wct                = 15;
+  tr2->total_param_count  = pattern_len * 2 + sizeof(smb_tr2_find2_t);
+  tr2->max_param_count    = 10; // ?? Why not the same or 12 ?
+  tr2->max_data_count     = 0xffff;
+  tr2->param_count        = tr2->total_param_count;
+  tr2->param_offset       = 68; // Offset of find_first_params in packet;
+  tr2->data_count         = 0;
+  tr2->data_offset        = 88; // Offset of pattern in packet
+  tr2->setup_count        = 1;
+  tr2->cmd                = SMB_TR2_FIND_FIRST;
+  tr2->bct                = sizeof(smb_tr2_find2_t) + pattern_len * 2 + 3;
+
+  find = (smb_tr2_find2_t *) tr2->payload;
+  find->attrs     = SMB_FIND2_ATTR_DEFAULT;
+  find->count     = 1366;     // ??
+  find->flags     = SMB_FIND2_FLAG_DEFAULT;
+  find->interest  = 0x0104;   // 'Find file both directory info'
+
+  smb_message_advance(msg, sizeof(smb_trans2_req_t));
+  smb_message_advance(msg, sizeof(smb_tr2_find2_t));
+  smb_message_put_utf16(msg, "", pattern, pattern_len);
+
+  // Adds padding at the end if necessary.
+  if (tr2->bct % 4)
+    smb_message_advance(msg, 4 - tr2->bct % 4);
+
+  res = smb_session_send_msg(s, msg);
+  smb_message_destroy(msg);
+  if (!res)
+  {
+    if (BDSM_DEBUG)
+      fprintf(stderr, "Unable to query pattern: %s\n", pattern);
+    return (NULL);
+  }
+
+  if (!smb_session_recv_msg(s, &reply)
+      || reply.packet->header.status != NT_STATUS_SUCCESS)
+  {
+    if (BDSM_DEBUG)
+      fprintf(stderr, "Unable to recv msg or failure for %s\n", pattern);
+    return (NULL);
+  }
+
+  return (smb_find_parse(&reply));
+}
+
+
+smb_file_t  *smb_stat(smb_session_t *s, smb_tid tid, const char *path)
+{
+  smb_message_t           *msg, reply;
+  smb_trans2_req_t        *tr2;
+  smb_trans2_resp_t       *tr2_resp;
+  smb_tr2_query_t         *query;
+  smb_tr2_path_info_t     *info;
+  smb_file_t              *file;
+  size_t                  path_len, msg_len;
+  int                     res;
+
+  assert(s != NULL && path != NULL && tid);
+
+  path_len  = strlen(path) + 1;
+  msg_len   = sizeof(smb_trans2_req_t) + sizeof(smb_tr2_query_t);
+  msg_len  += path_len * 2 + 3; // +3 for eventual padding
+
+  msg = smb_message_new(SMB_CMD_TRANS2, msg_len);
+  smb_message_set_default_flags(msg);
+  msg->packet->header.tid = tid;
+
+  tr2 = (smb_trans2_req_t *)msg->packet->payload;
+  tr2->wct                = 15;
+  tr2->total_param_count  = path_len * 2 + sizeof(smb_tr2_query_t);
+  tr2->max_param_count    = 2; // ?? Why not the same or 12 ?
+  tr2->max_data_count     = 0xffff;
+  tr2->param_count        = tr2->total_param_count;
+  tr2->param_offset       = 68; // Offset of find_first_params in packet;
+  tr2->data_count         = 0;
+  tr2->data_offset        = 96; // Offset of pattern in packet
+  tr2->setup_count        = 1;
+  tr2->cmd                = SMB_TR2_QUERY_PATH;
+  tr2->bct                = sizeof(smb_tr2_query_t) + path_len * 2 + 3;
+
+  query = (smb_tr2_query_t *)tr2->payload;
+  query->interest   = 0x0107;   // Query File All Info
+
+  smb_message_advance(msg, sizeof(smb_trans2_req_t));
+  smb_message_advance(msg, sizeof(smb_tr2_query_t));
+  smb_message_put_utf16(msg, "", path, path_len);
+
+  // Adds padding at the end if necessary.
+  if (msg->cursor % 4)
+  {
+    int padding = 4 - msg->cursor % 4;
+    tr2->bct += padding;
+    for (int i = 0; i < padding; i++)
+      smb_message_put8(msg, 0);
+  }
+
+  res = smb_session_send_msg(s, msg);
+  smb_message_destroy(msg);
+  if (!res)
+  {
+    if (BDSM_DEBUG)
+      fprintf(stderr, "Unable to query pattern: %s\n", path);
+    return (NULL);
+  }
+
+  if (!smb_session_recv_msg(s, &reply)
+      || reply.packet->header.status != NT_STATUS_SUCCESS)
+  {
+    if (BDSM_DEBUG)
+      fprintf(stderr, "Unable to recv msg or failure for %s\n", path);
+    return (NULL);
+  }
+
+  tr2_resp  = (smb_trans2_resp_t *)reply.packet->payload;
+  info      = (smb_tr2_path_info_t *)tr2_resp->payload;
+  file      = calloc(1, sizeof(smb_file_t));
+  assert(file != NULL);
+
+  file->name_len  = info->name_len;
+  file->name      = malloc(info->name_len);
+  assert(file->name != NULL);
+  memcpy(file->name, info->name, file->name_len);
+
+  file->created     = info->created;
+  file->accessed    = info->accessed;
+  file->written     = info->written;
+  file->changed     = info->changed;
+  file->alloc_size  = info->alloc_size;
+  file->size        = info->size;
+  file->attr        = info->attr;
+  file->is_dir      = info->is_dir;
+
+  return (file);
+}