Index: nselib/smb.lua
===================================================================
--- nselib/smb.lua	(revision 34010)
+++ nselib/smb.lua	(working copy)
@@ -2822,7 +2822,7 @@
         last_name = fe.fname
 
         coroutine.yield(fe)
-      until ( ne == 0 )
+      until ( ne == 0 or pos > response.data:len() )
       first = false
     until(stop_loop)
     return
Index: scripts/smb-enum-shares.nse
===================================================================
--- scripts/smb-enum-shares.nse	(revision 34083)
+++ scripts/smb-enum-shares.nse	(working copy)
@@ -126,6 +126,10 @@
   end
   response.account_used = string.format("%s%s", domain, stdnse.string_or_blank(username, '<blank>'))
 
+  if(host.registry['smb_shares'] == nil) then
+     host.registry['smb_shares'] = {}
+  end
+
   for i = 1, #shares, 1 do
     local share = shares[i]
     local share_output = stdnse.output_table()
@@ -135,6 +139,8 @@
       -- A share of 'NT_STATUS_OBJECT_NAME_NOT_FOUND' indicates this isn't a fileshare
       if(share['user_can_write'] == "NT_STATUS_OBJECT_NAME_NOT_FOUND") then
         share_output["Type"] = "Not a file share"
+      else
+	 table.insert(host.registry['smb_shares'], share.name)
       end
     else
       local details = share['details']
@@ -144,6 +150,12 @@
       share_output["Users"] = details.current_users
       share_output["Max Users"] = details.max_users
       share_output["Path"] = details.path
+
+      if (share_output["Type"] == "STYPE_DISKTREE" or
+	  share_output["Type"] == "STYPE_DISKTREE_TEMPORARY" or
+	  share_output["Type"] == "STYPE_DISKTREE_HIDDEN") then
+	 table.insert(host.registry['smb_shares'], share.name)
+      end
     end
     -- Print details for a file share
     if(share['anonymous_can_read'] and share['anonymous_can_write']) then
@@ -172,6 +184,10 @@
     response[share.name] = share_output
   end
 
+  if next(host.registry['smb_shares']) == nil then
+     host.registry['smb_shares'] = nil
+  end
+
   return response
 end
 
Index: scripts/smb-ls.nse
===================================================================
--- scripts/smb-ls.nse	(revision 34083)
+++ scripts/smb-ls.nse	(working copy)
@@ -30,8 +30,9 @@
 -- |     2007-12-02 00:42:40  <DIR>  WINDOWS
 -- |_    2007-12-02 00:22:38  <DIR>  wmpub
 --
--- @args smb-ls.share the share to connect to
--- @args smb-ls.path the path, relative to the share to list the contents from
+-- @args smb-ls.share [optional] the share to connect to
+-- @args smb-ls.shares [optional] a comma separated list of shares to connect to
+-- @args smb-ls.path [optional] the path, relative to the share to list the contents from
 -- @args smb-ls.pattern [optional] the search pattern to execute (default: *)
 -- @args smb-ls.maxdepth [optional] the maximum depth to recurse into a directory
 -- @args smb-ls.maxfiles [optional] return only a certain amount of files
@@ -41,9 +42,11 @@
 author = "Patrik Karlsson"
 license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
 categories = {"discovery", "safe"}
+dependencies = {"smb-enum-shares"}
 
+local arg_shares   = stdnse.get_script_args(SCRIPT_NAME .. '.shares')
 local arg_share    = stdnse.get_script_args(SCRIPT_NAME .. '.share')
-local arg_path     = stdnse.get_script_args(SCRIPT_NAME .. '.path')
+local arg_path     = stdnse.get_script_args(SCRIPT_NAME .. '.path') or '\\'
 local arg_pattern  = stdnse.get_script_args(SCRIPT_NAME .. '.pattern') or '*'
 local arg_maxfiles = tonumber(stdnse.get_script_args(SCRIPT_NAME .. '.maxfiles'))
 local arg_maxdepth = tonumber(stdnse.get_script_args(SCRIPT_NAME .. '.maxdepth'))
@@ -50,7 +53,9 @@
 local arg_checksum = stdnse.get_script_args(SCRIPT_NAME .. '.checksum')
 
 hostrule = function(host)
-  return ( smb.get_port(host) ~= nil and arg_share and arg_path )
+   return ( smb.get_port(host) ~= nil and
+	       (arg_shares or arg_share
+		   or host.registry['smb_shares'] ~= nil) )
 end
 
 -- checks whether the file entry is a directory
@@ -61,68 +66,92 @@
 local function fail(err) return ("\n  ERROR: %s"):format(err or "") end
 
 action = function(host)
-  local status, smbstate = smb.start_ex(host, true, true, arg_share, nil, nil, nil)
-  if ( not(status) ) then
-    return fail("Failed to authenticate to server (" .. smbstate .. ")")
+
+  -- use found shares if none has been specified
+  if arg_shares == nil then
+     if arg_share == nil then
+	arg_shares = host.registry['smb_shares']
+     else
+	arg_shares = {arg_share}
+     end
+  else
+     arg_shares = stdnse.strsplit(",", arg_shares)
   end
 
-  -- remove leading slash
-  arg_path = ( arg_path:sub(1,2) == '\\' and arg_path:sub(2) or arg_path )
+  local output = {}
 
-  -- fixup checksum argument
-  arg_checksum = ( arg_checksum == 'true' or arg_checksum == '1' ) and true or false
+  for _, share in ipairs(arg_shares) do
+     local status, smbstate = smb.start_ex(host, true, true, share,
+					   nil, nil, nil)
+     if ( not(status) ) then
+	table.insert(
+	   output,
+	   ("Failed to authenticate to server (%s) for directory of \\\\%s\\%s%s"):format(smbstate, stdnse.get_hostname(host), share, arg_path))
+	table.insert(output, "")
+     else
 
-  local options = { max_depth = arg_maxdepth, max_files = arg_maxfiles }
-  local depth, path, output, dirs = 0, arg_path, {}, {}
-  local file_count, dir_count, total_bytes = 0, 0, 0
+	table.insert(output, "")
 
-  repeat
-    local lstab = tab.new((arg_checksum and 4 or 3))
+	-- remove leading slash
+	arg_path = ( arg_path:sub(1,2) == '\\' and arg_path:sub(2) or arg_path )
 
-    for fe in smb.find_files(smbstate, path .. '\\' .. arg_pattern, options ) do
-      if ( arg_checksum and not(is_dir(fe)) ) then
-        local status, content = smb.file_read(host, arg_share, path .. '\\' .. fe.fname, nil, {file_create_disposition=1})
-        local sha1 = ( status and stdnse.tohex(openssl.sha1(content)) or "" )
-        tab.addrow(lstab, fe.created, (is_dir(fe) and '<DIR>' or fe.eof), fe.fname, sha1)
-      else
-        tab.addrow(lstab, fe.created, (is_dir(fe) and '<DIR>' or fe.eof), fe.fname)
-      end
+	-- fixup checksum argument
+	arg_checksum = ( arg_checksum == 'true' or arg_checksum == '1' ) and true or false
 
-      arg_maxfiles = ( arg_maxfiles and arg_maxfiles - 1 )
-      if ( arg_maxfiles == 0 ) then
-        break
-      end
+	local options = { max_depth = arg_maxdepth, max_files = arg_maxfiles }
+	local depth, path, dirs = 0, arg_path, {}
+	local file_count, dir_count, total_bytes = 0, 0, 0
 
-      if ( is_dir(fe) ) then
-        dir_count = dir_count + 1
-        if ( fe.fname ~= '.' and fe.fname ~= '..' ) then
-          table.insert(dirs, { depth = depth + 1, path = path .. '\\' .. fe.fname } )
-        end
-      else
-        total_bytes = total_bytes + fe.eof
-        file_count = file_count + 1
-      end
-    end
-    table.insert(output, { name = ("Directory of %s"):format( '\\\\' .. stdnse.get_hostname(host) .. '\\' .. arg_share .. path), tab.dump(lstab) })
+	repeat
+	   local lstab = tab.new((arg_checksum and 4 or 3))
 
-    path = nil
-    if ( #dirs ~= 0 ) then
-      local dir = table.remove(dirs, 1)
-      depth = dir.depth
-      if ( not(arg_maxdepth) or ( dir.depth < arg_maxdepth ) ) then
-        path = dir.path
-        table.insert(output, "")
-      end
-    end
-  until(not(path) or arg_maxfiles == 0)
+	   for fe in smb.find_files(smbstate, path .. '\\' .. arg_pattern, options ) do
+	      if ( arg_checksum and not(is_dir(fe)) ) then
+		 local status, content = smb.file_read(host, share, path .. '\\' .. fe.fname, nil, {file_create_disposition=1})
+		 local sha1 = ( status and stdnse.tohex(openssl.sha1(content)) or "" )
+		 tab.addrow(lstab, fe.created, (is_dir(fe) and '<DIR>' or fe.eof), fe.fname, sha1)
+	      else
+		 tab.addrow(lstab, fe.created, (is_dir(fe) and '<DIR>' or fe.eof), fe.fname)
+	      end
 
-  smb.stop(smbstate)
+	      arg_maxfiles = ( arg_maxfiles and arg_maxfiles - 1 )
+	      if ( arg_maxfiles == 0 ) then
+		 break
+	      end
 
-  local summary = { name = "Total Files Listed:",
-    ("%8d File(s)\t%d bytes"):format(file_count, total_bytes),
-    ("%8d Dir(s)"):format(dir_count) }
-  table.insert(output, "")
-  table.insert(output, summary)
+	      if ( is_dir(fe) ) then
+		 dir_count = dir_count + 1
+		 if ( fe.fname ~= '.' and fe.fname ~= '..' ) then
+		    table.insert(dirs, { depth = depth + 1, path = path .. '\\' .. fe.fname } )
+		 end
+	      else
+		 total_bytes = total_bytes + fe.eof
+		 file_count = file_count + 1
+	      end
+	   end
+	   table.insert(output, { name = ("Directory of %s"):format( '\\\\' .. stdnse.get_hostname(host) .. '\\' .. share .. path), tab.dump(lstab) })
 
+	   path = nil
+	   if ( #dirs ~= 0 ) then
+	      local dir = table.remove(dirs, 1)
+	      depth = dir.depth
+	      if ( not(arg_maxdepth) or ( dir.depth < arg_maxdepth ) ) then
+		 path = dir.path
+		 table.insert(output, "")
+	      end
+	   end
+	until(not(path) or arg_maxfiles == 0)
+
+	smb.stop(smbstate)
+
+	local summary = { name = "Total Files Listed:",
+			  ("%8d File(s)\t%d bytes"):format(file_count, total_bytes),
+			  ("%8d Dir(s)"):format(dir_count) }
+	table.insert(output, "")
+	table.insert(output, summary)
+	table.insert(output, "")
+     end
+  end
+
   return stdnse.format_output(true, output)
 end
