diff --git a/CHANGELOG b/CHANGELOG
index 993a95bf9..f745a187c 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,8 @@
# Nmap Changelog ($Id$); -*-text-*-
+o [NSE] Added smb-print-text script which prints specified text using SMB
+ shared printer. [Aleksandar Nikolic]
+
o [NSE] Added mrinfo script whiches queries a target router for multicast
information. [Hani Benhabiles]
diff --git a/scripts/script.db b/scripts/script.db
index 409df9b5f..8ad1af29c 100644
--- a/scripts/script.db
+++ b/scripts/script.db
@@ -341,6 +341,7 @@ Entry { filename = "smb-flood.nse", categories = { "dos", "intrusive", } }
Entry { filename = "smb-ls.nse", categories = { "discovery", "safe", } }
Entry { filename = "smb-mbenum.nse", categories = { "discovery", "safe", } }
Entry { filename = "smb-os-discovery.nse", categories = { "default", "discovery", "safe", } }
+Entry { filename = "smb-print-text.nse", categories = { "intrusive", } }
Entry { filename = "smb-psexec.nse", categories = { "intrusive", } }
Entry { filename = "smb-security-mode.nse", categories = { "default", "discovery", "safe", } }
Entry { filename = "smb-server-stats.nse", categories = { "discovery", "intrusive", } }
diff --git a/scripts/smb-print-text.nse b/scripts/smb-print-text.nse
new file mode 100644
index 000000000..cd6621965
--- /dev/null
+++ b/scripts/smb-print-text.nse
@@ -0,0 +1,134 @@
+local bin = require "bin"
+local msrpc = require "msrpc"
+local smb = require "smb"
+local string = require "string"
+local stdnse = require "stdnse"
+
+description = [[
+Script calls Print Spooler Service RPC functions to a shared printer
+to make it print text.
+
+In order to use the script, at least one printer needs to be shared
+over SMB. If no printer is specified, script tries to enumerate existing
+ones by calling LANMAN API which might not be always available.
+LANMAN is available by default on Windows XP, but not on Vista or Windows 7
+for example. In that case, you need to specify printer share name manualy
+using printer script argument. You can find out available shares
+by using smb-enum-shares script.
+
+Later versions of Windows require valid credentials by default
+which you can specify trough smb library arguments smbuser and
+smbpassword or other options.
+
+]]
+---
+-- @usage nmap -p 445 --script=smb-print-text
+--
+-- @output
+-- |_smb-print-text: Printer job started using MyPrinter printer share.
+--
+-- @args printer Printer share name. Optional, by default script tries to enumerate available printer shares.
+-- @args text Text to print. Either text or filename need to be specified.
+-- @args filename File to read text from (ASCII only).
+--
+
+author = "Aleksandar Nikolic"
+license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
+categories = {"intrusive"}
+
+hostrule = function(host)
+ return smb.get_port(host) ~= nil
+end
+
+action = function(host,port)
+ local status, smbstate
+ local text = stdnse.get_script_args(SCRIPT_NAME .. '.text')
+ local filename = stdnse.get_script_args(SCRIPT_NAME .. '.filename')
+ if (not text) and (not filename) then
+ stdnse.print_debug("Script requires either text or filename script argument.")
+ return false
+ end
+ local text_to_print
+ if text then
+ text_to_print = text
+ else
+ -- read text from file
+ local file = io.open(filename, "rb")
+ text_to_print = file:read("*all")
+ end
+ status, smbstate = msrpc.start_smb(host, msrpc.SPOOLSS_PATH,true)
+ if(status == false) then
+ stdnse.print_debug("SMB: " .. smbstate)
+ return false, smbstate
+ end
+
+ local bind_result
+ status, bind_result = msrpc.bind(smbstate,msrpc.SPOOLSS_UUID, msrpc.SPOOLSS_VERSION, nil)
+ if(status == false) then
+ msrpc.stop_smb(smbstate)
+ stdnse.print_debug("SMB: " .. bind_result)
+ return false, bind_result
+ end
+ local printer = stdnse.get_script_args(SCRIPT_NAME .. '.printer')
+ -- if printer not set find available printers
+ if not printer then
+ stdnse.print_debug("No printer specified, trying to find one...")
+ local lanman_result
+ local REMSmb_NetShareEnum_P = "WrLeh"
+ local REMSmb_share_info_1 = "B13BWz"
+ status, lanman_result = msrpc.call_lanmanapi(smbstate,0,REMSmb_NetShareEnum_P,REMSmb_share_info_1,bin.pack("ss",0x01,65406))
+ if status == false then
+ stdnse.print_debug("SMB: " .. lanman_result)
+ stdnse.print_debug("SMB: Looks like LANMAN API is not available. Try setting printer script arg.")
+ return false
+ end
+
+ local parameters = lanman_result.parameters
+ local data = lanman_result.data
+ local pos, status, convert, entry_count, available_entries = bin.unpack("s",data,pos+14)
+ pos, name = bin.unpack(" printer share.", printer)
+end