Преглед изворни кода

Implements Open/Close of file

Julien 'Lta' BALLET пре 11 година
родитељ
комит
6222e61e0d
11 измењених фајлова са 204 додато и 40 уклоњено
  1. 4 4
      README.md
  2. 1 0
      TODO.md
  3. 20 1
      dsm.c
  4. 23 5
      include/bdsm/smb_defs.h
  5. 2 1
      include/bdsm/smb_message.h
  6. 10 3
      include/bdsm/smb_session.h
  7. 3 1
      include/bdsm/smb_share.h
  8. 3 9
      src/context.c
  9. 23 8
      src/smb_message.c
  10. 11 5
      src/smb_session.c
  11. 104 3
      src/smb_share.c

+ 4 - 4
README.md

@@ -14,12 +14,12 @@ fix any error you have. (Hum... Enjoy!)
 
 Here's a list of features i intend to support in this project :
 * NETBIOS
-  ** Basic bi-directionnal NETBIOS name resolution
-  ** Hacky LAN SMB servers discovery (Listing all the smb servers on the LAN, no WINS, etc.)
-  ** Basic NETBIOS Session transport layer
+  ** Basic bi-directionnal NETBIOS name resolution [Done]
+  ** Hacky LAN SMB servers discovery (Listing all the smb servers on the LAN, no WINS, etc.) [Done]
+  ** Basic NETBIOS Session transport layer [Done]
 * SMB
   ** Support only required parts of 'NT LM 0.12' (aka CIFS?) dialect.
-  ** User based authentication
+  ** User based authentication [Done]
   ** List Shares
   ** Browse folders
   ** Read file

+ 1 - 0
TODO.md

@@ -6,3 +6,4 @@ done and i must not forget about.
 * Replace OpenSSL by Public Domain code or libgcrypt
 * Make libdsm work :D
 * Refactor and make this code readable
+* Support UTF8, right now we consider everything is ASCII

+ 20 - 1
dsm.c

@@ -103,7 +103,6 @@ int main(int ac, char **av)
   }
 
   smb_tid ipc  = smb_tree_connect(session, "\\\\CERBERE\\IPC$");
-  smb_tid test = smb_tree_connect(session, "\\\\CERBERE\\TEST");
 
   if (ipc == 0)
   {
@@ -112,6 +111,26 @@ int main(int ac, char **av)
   }
   fprintf(stderr, "Connected to IPC$ share\n");
 
+  smb_tid test = smb_tree_connect(session, "\\\\CERBERE\\TEST");
+  if (test)
+    fprintf(stderr, "Connected to Test share\n");
+  else
+  {
+    fprintf(stderr, "Unable to connect to Test share\n");
+    exit(42);
+  }
+
+  smb_fd fd = smb_fopen(session, test, "\\test.txt", SMB_MOD_RO);
+  if (fd)
+    fprintf(stderr, "Successfully opened \\test.txt: fd = 0x%.8x\n", fd);
+  else
+  {
+    fprintf(stderr, "Unable to open \\test.txt\n");
+    exit(42);
+  }
+
+  smb_fclose(session, fd);
+
   smb_session_destroy(session);
   bdsm_context_destroy(ctx);
 

+ 23 - 5
include/bdsm/smb_defs.h

@@ -96,6 +96,13 @@
 #define SMB_MOD_GENERIC_EXEC    (1 << 29)
 #define SMB_MOD_GENERIC_READ    (1 << 30)
 #define SMB_MOD_GENERIC_WRITE   (1 << 31)
+#define SMB_MOD_RW              (SMB_MOD_READ | SMB_MOD_WRITE | SMB_MOD_APPEND \
+                                | SMB_MOD_READ_EXT | SMB_MOD_WRITE_EXT \
+                                | SMB_MOD_READ_ATTR | SMB_MOD_WRITE_ATTR \
+                                | SMB_MOD_READ_CTL )
+#define SMB_MOD_RO              (SMB_MOD_READ | SMB_MOD_READ_EXT \
+                                | SMB_MOD_READ_ATTR | SMB_MOD_READ_CTL )
+
 // File attributes
 #define SMB_ATTR_RO             (1 << 0)
 #define SMB_ATTR_HIDDEN         (1 << 1)
@@ -130,6 +137,7 @@
 
 #define NT_STATUS_SUCCESS                   0x00000000
 #define NT_STATUS_MORE_PROCESSING_REQUIRED  0xc0000016
+#define NT_STATUS_ACCESS_DENIED             0xc0000022
 
 #define SMB_ANDX_MEMBERS  \
   uint8_t         andx;         /* 0xff when no other command (recommended :)*/\
@@ -232,11 +240,12 @@ typedef struct
 {
   uint8_t         wct;                // 24
   SMB_ANDX_MEMBERS
+  uint8_t         reserved2;
   uint16_t        path_length;
   uint32_t        flags;
   uint32_t        root_fid;
   uint32_t        access_mask;
-  uint64_t        alloc_sz;
+  uint64_t        alloc_size;
   uint32_t        file_attr;
   uint32_t        share_access;
   uint32_t        disposition;
@@ -258,9 +267,9 @@ typedef struct
   uint64_t        accessed;           // File last access time
   uint64_t        written;            // File last write time
   uint64_t        changed;            // File last modification time
-  uint32_t        file_attr;
-  uint64_t        alloc_sz;
-  uint64_t        eof;
+  uint32_t        attr;
+  uint64_t        alloc_size;
+  uint64_t        size;
   uint16_t        filetype;
   uint16_t        ipc_state;
   uint8_t         is_dir;
@@ -268,6 +277,15 @@ typedef struct
 } __attribute__((packed))   smb_create_resp_t;
 
 
+//// Close File
+
+typedef struct
+{
+  uint8_t         wct;                // 3
+  uint16_t        fid;
+  uint32_t        last_write;         // Not defined == 0xffffffff
+  uint16_t        bct;                // 0
+} __attribute__((packed))   smb_close_req_t;
 
 
 
@@ -284,7 +302,7 @@ typedef struct
   uint16_t        pid_high;     // Unused ?
   uint64_t        signature;    // Unused ?
   uint16_t        reserved;     // More usuned bit (we have so much BW :)
-  uint16_t        tree_id;      // SMB's file descriptor or service id ?
+  uint16_t        tid;          // A kind of fd for share. (tree_connect)
   uint16_t        pid;          // Process ID.
   uint16_t        uid;          // User ID.
   uint16_t        mux_id;       // Multiplex ID. Increment it sometimes.

+ 2 - 1
include/bdsm/smb_message.h

@@ -39,9 +39,10 @@ int             smb_message_put8(smb_message_t *msg, uint8_t data);
 int             smb_message_put16(smb_message_t *msg, uint16_t data);
 int             smb_message_put32(smb_message_t *msg, uint32_t data);
 int             smb_message_put64(smb_message_t *msg, uint32_t data);
-int             smb_message_put_utf16(smb_message_t *msg, const char *src_enc,
+size_t          smb_message_put_utf16(smb_message_t *msg, const char *src_enc,
                                       const char *str, size_t str_len);
 
 void            smb_message_set_default_flags(smb_message_t *msg);
+void            smb_message_set_andx_members(smb_message_t *msg);
 void            smb_message_flag(smb_message_t *msg, uint32_t flag, int value);
 #endif

+ 10 - 3
include/bdsm/smb_session.h

@@ -39,15 +39,22 @@ typedef uint16_t    smb_fid;
 // First 4 bytes are the TreeID (smb_tid), last 4 are the File ID (FUID)
 typedef uint32_t    smb_fd;
 
-#define SMB_FD_TID(fd)    ((smb_tid) fd >> 16)
-#define SMB_FD_FID(fd)    ((smb_fid) fd & 0x0000ffff)
-#define SMB_FD(tid, fid)  ((((smb_fd)tid) << 16) | (((smb_fd) fid))
+#define SMB_FD_TID(fd)    ((smb_tid)(fd >> 16))
+#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
 {
   smb_fid             fid;
   struct smb_file_s   *next;          // Next file in this share
   smb_tid             tid;
+  uint64_t            created;
+  uint64_t            accessed;
+  uint64_t            written;
+  uint64_t            changed;
+  uint64_t            alloc_size;
+  uint64_t            size;
+  uint32_t            attr;
 } smb_file_t;
 
 typedef struct smb_share_s

+ 3 - 1
include/bdsm/smb_share.h

@@ -29,9 +29,11 @@ int         smb_session_file_add(smb_session_t *s, smb_tid tid, smb_file_t *f);
 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);
 
+
 smb_tid     smb_tree_connect(smb_session_t *s, const char *path);
 int         smb_tree_disconnect(smb_session_t *s, smb_tid tid);
-smb_fd      smb_fopen(smb_session_t *s, smb_tid tid, const char *path);
+smb_fd      smb_fopen(smb_session_t *s, smb_tid tid, const char *path,
+                      uint32_t mod);
 void        smb_fclose(smb_session_t *s, smb_fd);
 
 #endif

+ 3 - 9
src/context.c

@@ -18,6 +18,7 @@
 
 #include <stdlib.h>
 #include <string.h>
+#include <assert.h>
 
 #include "bdsm/context.h"
 
@@ -25,13 +26,9 @@ bdsm_context_t    *bdsm_context_new()
 {
   bdsm_context_t  *ctx;
 
-  ctx = malloc(sizeof(bdsm_context_t));
-  memset((void *)ctx, 0, sizeof(bdsm_context_t));
+  ctx = calloc(1, sizeof(bdsm_context_t));
+  assert(ctx != NULL);
 
-  //if (BDSM_DEBUG)
-  //  event_enable_debug_mode();
-
-  //ctx->event_base = event_base_new();
   if (!(ctx->ns = netbios_ns_new()))
   {
     free(ctx);
@@ -46,8 +43,5 @@ void              bdsm_context_destroy(bdsm_context_t *ctx)
   if (!ctx)
     return;
 
-  // if (ctx->event_base)
-  //   event_base_free(ctx->event_base);
-
   free(ctx);
 }

+ 23 - 8
src/smb_message.c

@@ -74,6 +74,17 @@ int             smb_message_append(smb_message_t *msg, const void *data,
   return (1);
 }
 
+int             smb_message_advance(smb_message_t *msg, size_t size)
+{
+  assert(msg != NULL);
+
+  if (msg->cursor + size > msg->payload_size)
+    return (0);
+
+  msg->cursor += size;
+  return (1);
+}
+
 int             smb_message_put8(smb_message_t *msg, uint8_t data)
 {
   return(smb_message_append(msg, (void *)&data, 1));
@@ -94,7 +105,7 @@ int             smb_message_put64(smb_message_t *msg, uint32_t data)
     return(smb_message_append(msg, (void *)&data, 8));
 }
 
-int             smb_message_put_utf16(smb_message_t *msg, const char *src_enc,
+size_t          smb_message_put_utf16(smb_message_t *msg, const char *src_enc,
                                       const char *str, size_t str_len)
 {
   char          *utf_str;
@@ -105,7 +116,9 @@ int             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);
 
-  return(res);
+  if (res)
+    return(utf_str_len);
+  return (0);
 }
 
 void            smb_message_flag(smb_message_t *msg, uint32_t flag, int value)
@@ -133,13 +146,15 @@ void            smb_message_set_default_flags(smb_message_t *msg)
   msg->packet->header.flags2  = 0xc043; // w/o extended security;
 }
 
-int             smb_message_advance(smb_message_t *msg, size_t size)
+void            smb_message_set_andx_members(smb_message_t *msg)
 {
-  assert(msg != NULL);
+  // This could have been any type with the 'SMB_ANDX_MEMBERS';
+  smb_session_req_t   *req;
 
-  if (msg->cursor + size > msg->payload_size)
-    return (0);
+  assert(msg != NULL);
 
-  msg->cursor += size;
-  return (1);
+  req = (smb_session_req_t *)msg->packet->payload;
+  req->andx           = 0xff;
+  req->reserved       = 0;
+  req->andx_offset    = 0;
 }

+ 11 - 5
src/smb_session.c

@@ -69,6 +69,8 @@ int             smb_session_send_msg(smb_session_t *s, smb_message_t *msg)
   assert(s != NULL && s->state >= SMB_STATE_NETBIOS_OK && s->nb_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);
 
   packet_size   = sizeof(netbios_session_packet_t) + sizeof(smb_packet_t);
@@ -87,14 +89,15 @@ size_t          smb_session_recv_msg(smb_session_t *s, smb_message_t *msg)
   ssize_t                   recv_size;
   size_t                    payload_size;
 
-  assert(s != NULL && s->nb_session != NULL && msg != NULL);
+  assert(s != NULL && s->nb_session != NULL);
 
   recv_size = netbios_session_packet_recv(s->nb_session);
   if(recv_size <= 0)
     return (0);
 
   nb_packet   = (netbios_session_packet_t *)s->nb_session->recv_buffer;
-  msg->packet = (smb_packet_t *)nb_packet->payload;
+  if (msg != NULL)
+    msg->packet = (smb_packet_t *)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
@@ -105,10 +108,13 @@ size_t          smb_session_recv_msg(smb_session_t *s, smb_message_t *msg)
     return(0);
   }
 
-  msg->payload_size = payload_size - sizeof(smb_header_t);
-  msg->cursor       = 0;
+  if (msg != NULL)
+  {
+    msg->payload_size = payload_size - sizeof(smb_header_t);
+    msg->cursor       = 0;
+  }
 
-  return(msg->payload_size);
+  return (payload_size - sizeof(smb_header_t));
 }
 
 int             smb_negotiate(smb_session_t *s)

+ 104 - 3
src/smb_share.c

@@ -169,8 +169,7 @@ smb_tid         smb_tree_connect(smb_session_t *s, const char *path)
 
   // Packet headers
   smb_message_set_default_flags(req_msg);
-  req_msg->packet->header.uid      = s->uid;
-  req_msg->packet->header.tree_id  = 0xffff; // Behavior of libsmbclient
+  req_msg->packet->header.tid   = 0xffff; // Behavior of libsmbclient
 
   // Packet payload
   req = (smb_tree_connect_req_t *)req_msg->packet->payload;
@@ -203,7 +202,7 @@ smb_tid         smb_tree_connect(smb_session_t *s, const char *path)
   share = calloc(1, sizeof(smb_share_t));
   assert(share != NULL);
 
-  share->tid          = resp_msg.packet->header.tree_id;
+  share->tid          = resp_msg.packet->header.tid;
   share->opts         = resp->opt_support;
   share->rights       = resp->max_rights;
   share->guest_rights = resp->guest_rights;
@@ -219,3 +218,105 @@ int           smb_tree_disconnect(smb_session_t *s, smb_tid tid)
 
   return (0);
 }
+
+smb_fd      smb_fopen(smb_session_t *s, smb_tid tid, const char *path,
+                      uint32_t o_flags)
+{
+  smb_share_t       *share;
+  smb_file_t        *file;
+  smb_message_t     *req_msg, resp_msg;
+  smb_create_req_t  *req;
+  smb_create_resp_t *resp;
+  size_t            path_len;
+  int               res;
+
+  assert(s != NULL && path != NULL);
+  if ((share = smb_session_share_get(s, tid)) == NULL)
+    return (0);
+
+  req_msg = smb_message_new(SMB_CMD_CREATE, 128);
+
+  // Set SMB Headers
+  smb_message_set_default_flags(req_msg);
+  smb_message_set_andx_members(req_msg);
+  req_msg->packet->header.tid = tid;
+
+  // Create AndX Params
+  req = (smb_create_req_t *)req_msg->packet->payload;
+  req->wct            = 24;
+  req->flags          = 0;
+  req->root_fid       = 0;
+  req->access_mask    = o_flags;
+  req->alloc_size     = 0;
+  req->file_attr      = 0;
+  req->share_access   = SMB_SHARE_READ | SMB_SHARE_WRITE;
+  req->disposition    = 1;  // 1 = Open and file if doesn't exist
+  req->create_opts    = 0;  // We dont't support create
+  req->impersonation  = 2;  // ?????
+  req->security_flags = 0;  // ???
+
+  // Create AndX 'Body'
+  smb_message_advance(req_msg, sizeof(smb_create_req_t));
+  smb_message_put8(req_msg, 0);   // Align beginning of path
+  path_len = smb_message_put_utf16(req_msg, "", path, strlen(path) + 1);
+  // smb_message_put16(req_msg, 0);  // ??
+  req->path_length  = path_len;
+  req->bct          = path_len + 1;
+
+  res = smb_session_send_msg(s, req_msg);
+  smb_message_destroy(req_msg);
+  if (!res)
+    return (0);
+
+  if (!smb_session_recv_msg(s, &resp_msg))
+    return (0);
+  if (resp_msg.packet->header.status != NT_STATUS_SUCCESS)
+    return (0);
+
+  resp = (smb_create_resp_t *)resp_msg.packet->payload;
+  file = calloc(1, sizeof(smb_file_t));
+  assert(file != NULL);
+
+  file->fid           = resp->fid;
+  file->tid           = tid;
+  file->created       = resp->created;
+  file->accessed      = resp->accessed;
+  file->written       = resp->written;
+  file->changed       = resp->changed;
+  file->alloc_size    = resp->alloc_size;
+  file->size          = resp->size;
+  file->attr          = resp->attr;
+
+  smb_session_file_add(s, tid, file); // XXX Check return
+
+  return (SMB_FD(tid, file->fid));
+}
+
+void        smb_fclose(smb_session_t *s, smb_fd fd)
+{
+  smb_file_t        *file;
+  smb_message_t     *msg;
+  smb_close_req_t   *req;
+
+  assert(s != NULL && fd);
+
+  if ((file = smb_session_file_remove(s, fd)) == NULL)
+    return;
+
+  msg = smb_message_new(SMB_CMD_CLOSE, 64);
+  req = (smb_close_req_t *)msg->packet->payload;
+
+  msg->packet->header.tid = SMB_FD_TID(fd);
+
+  smb_message_advance(msg, sizeof(smb_close_req_t));
+  req->wct        = 3;
+  req->fid        = SMB_FD_FID(fd);
+  req->last_write = ~0;
+  req->bct        = 0;
+
+  // We don't check for succes or failure, since we actually don't really
+  // care about creating a potentiel leak server side.
+  smb_session_send_msg(s, msg);
+  smb_session_recv_msg(s, 0);
+}
+