smbserver.py 191 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168
  1. # Copyright (c) 2003-2016 CORE Security Technologies
  2. #
  3. # This software is provided under under a slightly modified version
  4. # of the Apache Software License. See the accompanying LICENSE file
  5. # for more information.
  6. #
  7. # Author: Alberto Solino (@agsolino)
  8. #
  9. # TODO:
  10. # [-] Functions should return NT error codes
  11. # [-] Handling errors in all situations, right now it's just raising exceptions.
  12. # [*] Standard authentication support
  13. # [ ] Organize the connectionData stuff
  14. # [*] Add capability to send a bad user ID if the user is not authenticated,
  15. # right now you can ask for any command without actually being authenticated
  16. # [ ] PATH TRAVERSALS EVERYWHERE.. BE WARNED!
  17. # [ ] Check the credentials.. now we're just letting everybody to log in.
  18. # [ ] Check error situation (now many places assume the right data is coming)
  19. # [ ] Implement IPC to the main process so the connectionData is on a single place
  20. # [ ] Hence.. implement locking
  21. # estamos en la B
  22. from __future__ import with_statement
  23. import calendar
  24. import socket
  25. import time
  26. import datetime
  27. import struct
  28. import ConfigParser
  29. import SocketServer
  30. import threading
  31. import logging
  32. import logging.config
  33. import ntpath
  34. import os
  35. import fnmatch
  36. import errno
  37. import sys
  38. import random
  39. import shutil
  40. from binascii import hexlify
  41. # For signing
  42. from impacket import smb, nmb, ntlm, uuid, LOG
  43. from impacket import smb3structs as smb2
  44. from impacket.spnego import SPNEGO_NegTokenInit, TypesMech, MechTypes, SPNEGO_NegTokenResp, ASN1_AID, ASN1_SUPPORTED_MECH
  45. from impacket.nt_errors import STATUS_NO_MORE_FILES, STATUS_NETWORK_NAME_DELETED, STATUS_INVALID_PARAMETER, \
  46. STATUS_FILE_CLOSED, STATUS_MORE_PROCESSING_REQUIRED, STATUS_OBJECT_PATH_NOT_FOUND, STATUS_DIRECTORY_NOT_EMPTY, \
  47. STATUS_FILE_IS_A_DIRECTORY, STATUS_NOT_IMPLEMENTED, STATUS_INVALID_HANDLE, STATUS_OBJECT_NAME_COLLISION, \
  48. STATUS_NO_SUCH_FILE, STATUS_CANCELLED, STATUS_OBJECT_NAME_NOT_FOUND, STATUS_SUCCESS, STATUS_ACCESS_DENIED, \
  49. STATUS_NOT_SUPPORTED, STATUS_INVALID_DEVICE_REQUEST, STATUS_FS_DRIVER_REQUIRED, STATUS_INVALID_INFO_CLASS
  50. # These ones not defined in nt_errors
  51. STATUS_SMB_BAD_UID = 0x005B0002
  52. STATUS_SMB_BAD_TID = 0x00050002
  53. # Utility functions
  54. # and general functions.
  55. # There are some common functions that can be accessed from more than one SMB
  56. # command (or either TRANSACTION). That's why I'm putting them here
  57. # TODO: Return NT ERROR Codes
  58. def outputToJohnFormat(challenge, username, domain, lmresponse, ntresponse):
  59. # We don't want to add a possible failure here, since this is an
  60. # extra bonus. We try, if it fails, returns nothing
  61. ret_value = ''
  62. try:
  63. if len(ntresponse) > 24:
  64. # Extended Security - NTLMv2
  65. ret_value = {'hash_string':'%s::%s:%s:%s:%s' % (username.decode('utf-16le'), domain.decode('utf-16le'), hexlify(challenge), hexlify(ntresponse)[:32], hexlify(ntresponse)[32:]), 'hash_version':'ntlmv2'}
  66. else:
  67. # NTLMv1
  68. ret_value = {'hash_string':'%s::%s:%s:%s:%s' % (username.decode('utf-16le'), domain.decode('utf-16le'), hexlify(lmresponse), hexlify(ntresponse), hexlify(challenge)), 'hash_version':'ntlm'}
  69. except:
  70. # Let's try w/o decoding Unicode
  71. try:
  72. if len(ntresponse) > 24:
  73. # Extended Security - NTLMv2
  74. ret_value = {'hash_string':'%s::%s:%s:%s:%s' % (username, domain, hexlify(challenge), hexlify(ntresponse)[:32], hexlify(ntresponse)[32:]), 'hash_version':'ntlmv2'}
  75. else:
  76. # NTLMv1
  77. ret_value = {'hash_string':'%s::%s:%s:%s:%s' % (username, domain, hexlify(lmresponse), hexlify(ntresponse), hexlify(challenge)), 'hash_version':'ntlm'}
  78. except Exception, e:
  79. LOG.error("outputToJohnFormat: %s" % e)
  80. pass
  81. return ret_value
  82. def writeJohnOutputToFile(hash_string, hash_version, file_name):
  83. fn_data = os.path.splitext(file_name)
  84. if hash_version == "ntlmv2":
  85. output_filename = fn_data[0] + "_ntlmv2" + fn_data[1]
  86. else:
  87. output_filename = fn_data[0] + "_ntlm" + fn_data[1]
  88. with open(output_filename,"a") as f:
  89. f.write(hash_string)
  90. f.write('\n')
  91. def decodeSMBString( flags, text ):
  92. if flags & smb.SMB.FLAGS2_UNICODE:
  93. return text.decode('utf-16le')
  94. else:
  95. return text
  96. def encodeSMBString( flags, text ):
  97. if flags & smb.SMB.FLAGS2_UNICODE:
  98. return (text).encode('utf-16le')
  99. else:
  100. return text
  101. def getFileTime(t):
  102. t *= 10000000
  103. t += 116444736000000000
  104. return t
  105. def getUnixTime(t):
  106. t -= 116444736000000000
  107. t /= 10000000
  108. return t
  109. def getSMBDate(t):
  110. # TODO: Fix this :P
  111. d = datetime.date.fromtimestamp(t)
  112. year = d.year - 1980
  113. ret = (year << 8) + (d.month << 4) + d.day
  114. return ret
  115. def getSMBTime(t):
  116. # TODO: Fix this :P
  117. d = datetime.datetime.fromtimestamp(t)
  118. return (d.hour << 8) + (d.minute << 4) + d.second
  119. def getShares(connId, smbServer):
  120. config = smbServer.getServerConfig()
  121. sections = config.sections()
  122. # Remove the global one
  123. del(sections[sections.index('global')])
  124. shares = {}
  125. for i in sections:
  126. shares[i] = dict(config.items(i))
  127. return shares
  128. def searchShare(connId, share, smbServer):
  129. config = smbServer.getServerConfig()
  130. if config.has_section(share):
  131. return dict(config.items(share))
  132. else:
  133. return None
  134. def openFile(path,fileName, accessMode, fileAttributes, openMode):
  135. fileName = os.path.normpath(fileName.replace('\\','/'))
  136. errorCode = 0
  137. if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
  138. # strip leading '/'
  139. fileName = fileName[1:]
  140. pathName = os.path.join(path,fileName)
  141. mode = 0
  142. # Check the Open Mode
  143. if openMode & 0x10:
  144. # If the file does not exist, create it.
  145. mode = os.O_CREAT
  146. else:
  147. # If file does not exist, return an error
  148. if os.path.exists(pathName) is not True:
  149. errorCode = STATUS_NO_SUCH_FILE
  150. return 0,mode, pathName, errorCode
  151. if os.path.isdir(pathName) and (fileAttributes & smb.ATTR_DIRECTORY) == 0:
  152. # Request to open a normal file and this is actually a directory
  153. errorCode = STATUS_FILE_IS_A_DIRECTORY
  154. return 0, mode, pathName, errorCode
  155. # Check the Access Mode
  156. if accessMode & 0x7 == 1:
  157. mode |= os.O_WRONLY
  158. elif accessMode & 0x7 == 2:
  159. mode |= os.O_RDWR
  160. else:
  161. mode = os.O_RDONLY
  162. try:
  163. if sys.platform == 'win32':
  164. mode |= os.O_BINARY
  165. fid = os.open(pathName, mode)
  166. except Exception, e:
  167. LOG.error("openFile: %s,%s" % (pathName, mode) ,e)
  168. fid = 0
  169. errorCode = STATUS_ACCESS_DENIED
  170. return fid, mode, pathName, errorCode
  171. def queryFsInformation(path, filename, level=0):
  172. if isinstance(filename,unicode):
  173. encoding = 'utf-16le'
  174. flags = smb.SMB.FLAGS2_UNICODE
  175. else:
  176. encoding = 'ascii'
  177. flags = 0
  178. fileName = os.path.normpath(filename.replace('\\','/'))
  179. if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
  180. # strip leading '/'
  181. fileName = fileName[1:]
  182. pathName = os.path.join(path,fileName)
  183. fileSize = os.path.getsize(pathName)
  184. (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(pathName)
  185. if level == smb.SMB_QUERY_FS_ATTRIBUTE_INFO or level == smb2.SMB2_FILESYSTEM_ATTRIBUTE_INFO:
  186. data = smb.SMBQueryFsAttributeInfo()
  187. data['FileSystemAttributes'] = smb.FILE_CASE_SENSITIVE_SEARCH | smb.FILE_CASE_PRESERVED_NAMES
  188. data['MaxFilenNameLengthInBytes'] = 255
  189. data['LengthOfFileSystemName'] = len('XTFS')*2
  190. data['FileSystemName'] = 'XTFS'.encode('utf-16le')
  191. return data.getData()
  192. elif level == smb.SMB_INFO_VOLUME:
  193. data = smb.SMBQueryFsInfoVolume( flags = flags )
  194. data['VolumeLabel'] = 'SHARE'.encode(encoding)
  195. return data.getData()
  196. elif level == smb.SMB_QUERY_FS_VOLUME_INFO or level == smb2.SMB2_FILESYSTEM_VOLUME_INFO:
  197. data = smb.SMBQueryFsVolumeInfo()
  198. data['VolumeLabel'] = ''
  199. data['VolumeCreationTime'] = getFileTime(ctime)
  200. return data.getData()
  201. elif level == smb.SMB_QUERY_FS_SIZE_INFO:
  202. data = smb.SMBQueryFsSizeInfo()
  203. return data.getData()
  204. elif level == smb.FILE_FS_FULL_SIZE_INFORMATION:
  205. data = smb.SMBFileFsFullSizeInformation()
  206. return data.getData()
  207. elif level == smb.FILE_FS_SIZE_INFORMATION:
  208. data = smb.FileFsSizeInformation()
  209. return data.getData()
  210. else:
  211. lastWriteTime = mtime
  212. attribs = 0
  213. if os.path.isdir(pathName):
  214. attribs |= smb.SMB_FILE_ATTRIBUTE_DIRECTORY
  215. if os.path.isfile(pathName):
  216. attribs |= smb.SMB_FILE_ATTRIBUTE_NORMAL
  217. fileAttributes = attribs
  218. return fileSize, lastWriteTime, fileAttributes
  219. def findFirst2(path, fileName, level, searchAttributes, isSMB2 = False):
  220. # TODO: Depending on the level, this could be done much simpler
  221. #print "FindFirs2 path:%s, filename:%s" % (path, fileName)
  222. fileName = os.path.normpath(fileName.replace('\\','/'))
  223. # Let's choose the right encoding depending on the request
  224. if isinstance(fileName,unicode):
  225. encoding = 'utf-16le'
  226. flags = smb.SMB.FLAGS2_UNICODE
  227. else:
  228. encoding = 'ascii'
  229. flags = 0
  230. if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
  231. # strip leading '/'
  232. fileName = fileName[1:]
  233. pathName = os.path.join(path,fileName)
  234. files = []
  235. if pathName.find('*') == -1 and pathName.find('?') == -1:
  236. # No search patterns
  237. pattern = ''
  238. else:
  239. pattern = os.path.basename(pathName)
  240. dirName = os.path.dirname(pathName)
  241. # Always add . and .. Not that important for Windows, but Samba whines if
  242. # not present (for * search only)
  243. if pattern == '*':
  244. files.append(os.path.join(dirName,'.'))
  245. files.append(os.path.join(dirName,'..'))
  246. if pattern != '':
  247. for file in os.listdir(dirName):
  248. if fnmatch.fnmatch(file.lower(),pattern.lower()):
  249. entry = os.path.join(dirName, file)
  250. if os.path.isdir(entry):
  251. if searchAttributes & smb.ATTR_DIRECTORY:
  252. files.append(entry)
  253. else:
  254. files.append(entry)
  255. else:
  256. if os.path.exists(pathName):
  257. files.append(pathName)
  258. searchResult = []
  259. searchCount = len(files)
  260. errorCode = STATUS_SUCCESS
  261. for i in files:
  262. if level == smb.SMB_FIND_FILE_BOTH_DIRECTORY_INFO or level == smb2.SMB2_FILE_BOTH_DIRECTORY_INFO:
  263. item = smb.SMBFindFileBothDirectoryInfo( flags = flags )
  264. elif level == smb.SMB_FIND_FILE_DIRECTORY_INFO or level == smb2.SMB2_FILE_DIRECTORY_INFO:
  265. item = smb.SMBFindFileDirectoryInfo( flags = flags )
  266. elif level == smb.SMB_FIND_FILE_FULL_DIRECTORY_INFO or level == smb2.SMB2_FULL_DIRECTORY_INFO:
  267. item = smb.SMBFindFileFullDirectoryInfo( flags = flags )
  268. elif level == smb.SMB_FIND_INFO_STANDARD:
  269. item = smb.SMBFindInfoStandard( flags = flags )
  270. elif level == smb.SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO or level == smb2.SMB2_FILE_ID_FULL_DIRECTORY_INFO:
  271. item = smb.SMBFindFileIdFullDirectoryInfo( flags = flags )
  272. elif level == smb.SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO or level == smb2.SMB2_FILE_ID_BOTH_DIRECTORY_INFO:
  273. item = smb.SMBFindFileIdBothDirectoryInfo( flags = flags )
  274. elif level == smb.SMB_FIND_FILE_NAMES_INFO or level == smb2.SMB2_FILE_NAMES_INFO:
  275. item = smb.SMBFindFileNamesInfo( flags = flags )
  276. else:
  277. LOG.error("Wrong level %d!" % level)
  278. return searchResult, searchCount, STATUS_NOT_SUPPORTED
  279. (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(i)
  280. if os.path.isdir(i):
  281. item['ExtFileAttributes'] = smb.ATTR_DIRECTORY
  282. else:
  283. item['ExtFileAttributes'] = smb.ATTR_NORMAL | smb.ATTR_ARCHIVE
  284. item['FileName'] = os.path.basename(i).encode(encoding)
  285. if level == smb.SMB_FIND_FILE_BOTH_DIRECTORY_INFO or level == smb.SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO or level == smb2.SMB2_FILE_ID_BOTH_DIRECTORY_INFO or level == smb2.SMB2_FILE_BOTH_DIRECTORY_INFO:
  286. item['EaSize'] = 0
  287. item['EndOfFile'] = size
  288. item['AllocationSize'] = size
  289. item['CreationTime'] = getFileTime(ctime)
  290. item['LastAccessTime'] = getFileTime(atime)
  291. item['LastWriteTime'] = getFileTime(mtime)
  292. item['LastChangeTime'] = getFileTime(mtime)
  293. item['ShortName'] = '\x00'*24
  294. item['FileName'] = os.path.basename(i).encode(encoding)
  295. padLen = (8-(len(item) % 8)) % 8
  296. item['NextEntryOffset'] = len(item) + padLen
  297. elif level == smb.SMB_FIND_FILE_DIRECTORY_INFO:
  298. item['EndOfFile'] = size
  299. item['AllocationSize'] = size
  300. item['CreationTime'] = getFileTime(ctime)
  301. item['LastAccessTime'] = getFileTime(atime)
  302. item['LastWriteTime'] = getFileTime(mtime)
  303. item['LastChangeTime'] = getFileTime(mtime)
  304. item['FileName'] = os.path.basename(i).encode(encoding)
  305. padLen = (8-(len(item) % 8)) % 8
  306. item['NextEntryOffset'] = len(item) + padLen
  307. elif level == smb.SMB_FIND_FILE_FULL_DIRECTORY_INFO or level == smb.SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO or level == smb2.SMB2_FULL_DIRECTORY_INFO:
  308. item['EaSize'] = 0
  309. item['EndOfFile'] = size
  310. item['AllocationSize'] = size
  311. item['CreationTime'] = getFileTime(ctime)
  312. item['LastAccessTime'] = getFileTime(atime)
  313. item['LastWriteTime'] = getFileTime(mtime)
  314. item['LastChangeTime'] = getFileTime(mtime)
  315. padLen = (8-(len(item) % 8)) % 8
  316. item['NextEntryOffset'] = len(item) + padLen
  317. elif level == smb.SMB_FIND_INFO_STANDARD:
  318. item['EaSize'] = size
  319. item['CreationDate'] = getSMBDate(ctime)
  320. item['CreationTime'] = getSMBTime(ctime)
  321. item['LastAccessDate'] = getSMBDate(atime)
  322. item['LastAccessTime'] = getSMBTime(atime)
  323. item['LastWriteDate'] = getSMBDate(mtime)
  324. item['LastWriteTime'] = getSMBTime(mtime)
  325. searchResult.append(item)
  326. # No more files
  327. if (level >= smb.SMB_FIND_FILE_DIRECTORY_INFO or isSMB2 == True) and searchCount > 0:
  328. searchResult[-1]['NextEntryOffset'] = 0
  329. return searchResult, searchCount, errorCode
  330. def queryFileInformation(path, filename, level):
  331. #print "queryFileInfo path: %s, filename: %s, level:0x%x" % (path,filename,level)
  332. return queryPathInformation(path,filename, level)
  333. def queryPathInformation(path, filename, level):
  334. # TODO: Depending on the level, this could be done much simpler
  335. #print "queryPathInfo path: %s, filename: %s, level:0x%x" % (path,filename,level)
  336. try:
  337. errorCode = 0
  338. fileName = os.path.normpath(filename.replace('\\','/'))
  339. if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\') and path != '':
  340. # strip leading '/'
  341. fileName = fileName[1:]
  342. pathName = os.path.join(path,fileName)
  343. if os.path.exists(pathName):
  344. (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(pathName)
  345. if level == smb.SMB_QUERY_FILE_BASIC_INFO:
  346. infoRecord = smb.SMBQueryFileBasicInfo()
  347. infoRecord['CreationTime'] = getFileTime(ctime)
  348. infoRecord['LastAccessTime'] = getFileTime(atime)
  349. infoRecord['LastWriteTime'] = getFileTime(mtime)
  350. infoRecord['LastChangeTime'] = getFileTime(mtime)
  351. if os.path.isdir(pathName):
  352. infoRecord['ExtFileAttributes'] = smb.ATTR_DIRECTORY
  353. else:
  354. infoRecord['ExtFileAttributes'] = smb.ATTR_NORMAL | smb.ATTR_ARCHIVE
  355. elif level == smb.SMB_QUERY_FILE_STANDARD_INFO:
  356. infoRecord = smb.SMBQueryFileStandardInfo()
  357. infoRecord['AllocationSize'] = size
  358. infoRecord['EndOfFile'] = size
  359. if os.path.isdir(pathName):
  360. infoRecord['Directory'] = 1
  361. else:
  362. infoRecord['Directory'] = 0
  363. elif level == smb.SMB_QUERY_FILE_ALL_INFO or level == smb2.SMB2_FILE_ALL_INFO:
  364. infoRecord = smb.SMBQueryFileAllInfo()
  365. infoRecord['CreationTime'] = getFileTime(ctime)
  366. infoRecord['LastAccessTime'] = getFileTime(atime)
  367. infoRecord['LastWriteTime'] = getFileTime(mtime)
  368. infoRecord['LastChangeTime'] = getFileTime(mtime)
  369. if os.path.isdir(pathName):
  370. infoRecord['ExtFileAttributes'] = smb.ATTR_DIRECTORY
  371. else:
  372. infoRecord['ExtFileAttributes'] = smb.ATTR_NORMAL | smb.ATTR_ARCHIVE
  373. infoRecord['AllocationSize'] = size
  374. infoRecord['EndOfFile'] = size
  375. if os.path.isdir(pathName):
  376. infoRecord['Directory'] = 1
  377. else:
  378. infoRecord['Directory'] = 0
  379. infoRecord['FileName'] = filename.encode('utf-16le')
  380. elif level == smb2.SMB2_FILE_NETWORK_OPEN_INFO:
  381. infoRecord = smb.SMBFileNetworkOpenInfo()
  382. infoRecord['CreationTime'] = getFileTime(ctime)
  383. infoRecord['LastAccessTime'] = getFileTime(atime)
  384. infoRecord['LastWriteTime'] = getFileTime(mtime)
  385. infoRecord['ChangeTime'] = getFileTime(mtime)
  386. infoRecord['AllocationSize'] = size
  387. infoRecord['EndOfFile'] = size
  388. if os.path.isdir(pathName):
  389. infoRecord['FileAttributes'] = smb.ATTR_DIRECTORY
  390. else:
  391. infoRecord['FileAttributes'] = smb.ATTR_NORMAL | smb.ATTR_ARCHIVE
  392. elif level == smb.SMB_QUERY_FILE_EA_INFO or level == smb2.SMB2_FILE_EA_INFO:
  393. infoRecord = smb.SMBQueryFileEaInfo()
  394. elif level == smb2.SMB2_FILE_STREAM_INFO:
  395. infoRecord = smb.SMBFileStreamInformation()
  396. else:
  397. LOG.error('Unknown level for query path info! 0x%x' % level)
  398. # UNSUPPORTED
  399. return None, STATUS_NOT_SUPPORTED
  400. return infoRecord, errorCode
  401. else:
  402. # NOT FOUND
  403. return None, STATUS_OBJECT_NAME_NOT_FOUND
  404. except Exception, e:
  405. LOG.error('queryPathInfo: %s' % e)
  406. raise
  407. def queryDiskInformation(path):
  408. # TODO: Do something useful here :)
  409. # For now we just return fake values
  410. totalUnits = 65535
  411. freeUnits = 65535
  412. return totalUnits, freeUnits
  413. # Here we implement the NT transaction handlers
  414. class NTTRANSCommands:
  415. def default(self, connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
  416. pass
  417. # Here we implement the NT transaction handlers
  418. class TRANSCommands:
  419. @staticmethod
  420. def lanMan(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
  421. # Minimal [MS-RAP] implementation, just to return the shares
  422. connData = smbServer.getConnectionData(connId)
  423. respSetup = ''
  424. respParameters = ''
  425. respData = ''
  426. errorCode = STATUS_SUCCESS
  427. if struct.unpack('<H',parameters[:2])[0] == 0:
  428. # NetShareEnum Request
  429. netShareEnum = smb.SMBNetShareEnum(parameters)
  430. if netShareEnum['InfoLevel'] == 1:
  431. shares = getShares(connId, smbServer)
  432. respParameters = smb.SMBNetShareEnumResponse()
  433. respParameters['EntriesReturned'] = len(shares)
  434. respParameters['EntriesAvailable'] = len(shares)
  435. tailData = ''
  436. for i in shares:
  437. # NetShareInfo1 len == 20
  438. entry = smb.NetShareInfo1()
  439. entry['NetworkName'] = i + '\x00'*(13-len(i))
  440. entry['Type'] = int(shares[i]['share type'])
  441. # (beto) If offset == 0 it crashes explorer.exe on windows 7
  442. entry['RemarkOffsetLow'] = 20 * len(shares) + len(tailData)
  443. respData += entry.getData()
  444. if shares[i].has_key('comment'):
  445. tailData += shares[i]['comment'] + '\x00'
  446. else:
  447. tailData += '\x00'
  448. respData += tailData
  449. else:
  450. # We don't support other info levels
  451. errorCode = STATUS_NOT_SUPPORTED
  452. elif struct.unpack('<H',parameters[:2])[0] == 13:
  453. # NetrServerGetInfo Request
  454. respParameters = smb.SMBNetServerGetInfoResponse()
  455. netServerInfo = smb.SMBNetServerInfo1()
  456. netServerInfo['ServerName'] = smbServer.getServerName()
  457. respData = str(netServerInfo)
  458. respParameters['TotalBytesAvailable'] = len(respData)
  459. elif struct.unpack('<H',parameters[:2])[0] == 1:
  460. # NetrShareGetInfo Request
  461. request = smb.SMBNetShareGetInfo(parameters)
  462. respParameters = smb.SMBNetShareGetInfoResponse()
  463. shares = getShares(connId, smbServer)
  464. share = shares[request['ShareName'].upper()]
  465. shareInfo = smb.NetShareInfo1()
  466. shareInfo['NetworkName'] = request['ShareName'].upper() + '\x00'
  467. shareInfo['Type'] = int(share['share type'])
  468. respData = shareInfo.getData()
  469. if share.has_key('comment'):
  470. shareInfo['RemarkOffsetLow'] = len(respData)
  471. respData += share['comment'] + '\x00'
  472. respParameters['TotalBytesAvailable'] = len(respData)
  473. else:
  474. # We don't know how to handle anything else
  475. errorCode = STATUS_NOT_SUPPORTED
  476. smbServer.setConnectionData(connId, connData)
  477. return respSetup, respParameters, respData, errorCode
  478. @staticmethod
  479. def transactNamedPipe(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
  480. connData = smbServer.getConnectionData(connId)
  481. respSetup = ''
  482. respParameters = ''
  483. respData = ''
  484. errorCode = STATUS_SUCCESS
  485. SMBCommand = smb.SMBCommand(recvPacket['Data'][0])
  486. transParameters= smb.SMBTransaction_Parameters(SMBCommand['Parameters'])
  487. # Extract the FID
  488. fid = struct.unpack('<H', transParameters['Setup'][2:])[0]
  489. if connData['OpenedFiles'].has_key(fid):
  490. fileHandle = connData['OpenedFiles'][fid]['FileHandle']
  491. if fileHandle != PIPE_FILE_DESCRIPTOR:
  492. os.write(fileHandle,data)
  493. respData = os.read(fileHandle,data)
  494. else:
  495. sock = connData['OpenedFiles'][fid]['Socket']
  496. sock.send(data)
  497. respData = sock.recv(maxDataCount)
  498. else:
  499. errorCode = STATUS_INVALID_HANDLE
  500. smbServer.setConnectionData(connId, connData)
  501. return respSetup, respParameters, respData, errorCode
  502. # Here we implement the transaction2 handlers
  503. class TRANS2Commands:
  504. # All these commands return setup, parameters, data, errorCode
  505. @staticmethod
  506. def setPathInformation(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
  507. connData = smbServer.getConnectionData(connId)
  508. respSetup = ''
  509. respParameters = ''
  510. respData = ''
  511. errorCode = STATUS_SUCCESS
  512. setPathInfoParameters = smb.SMBSetPathInformation_Parameters(flags = recvPacket['Flags2'], data = parameters)
  513. if connData['ConnectedShares'].has_key(recvPacket['Tid']):
  514. path = connData['ConnectedShares'][recvPacket['Tid']]['path']
  515. fileName = decodeSMBString(recvPacket['Flags2'], setPathInfoParameters['FileName'])
  516. fileName = os.path.normpath(fileName.replace('\\','/'))
  517. if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\') and path != '':
  518. # strip leading '/'
  519. fileName = fileName[1:]
  520. pathName = os.path.join(path,fileName)
  521. if os.path.exists(pathName):
  522. informationLevel = setPathInfoParameters['InformationLevel']
  523. if informationLevel == smb.SMB_SET_FILE_BASIC_INFO:
  524. infoRecord = smb.SMBSetFileBasicInfo(data)
  525. # Creation time won't be set, the other ones we play with.
  526. atime = infoRecord['LastAccessTime']
  527. if atime == 0:
  528. atime = -1
  529. else:
  530. atime = getUnixTime(atime)
  531. mtime = infoRecord['LastWriteTime']
  532. if mtime == 0:
  533. mtime = -1
  534. else:
  535. mtime = getUnixTime(mtime)
  536. if mtime != -1 or atime != -1:
  537. os.utime(pathName,(atime,mtime))
  538. else:
  539. smbServer.log('Unknown level for set path info! 0x%x' % setPathInfoParameters['InformationLevel'], logging.ERROR)
  540. # UNSUPPORTED
  541. errorCode = STATUS_NOT_SUPPORTED
  542. else:
  543. errorCode = STATUS_OBJECT_NAME_NOT_FOUND
  544. if errorCode == STATUS_SUCCESS:
  545. respParameters = smb.SMBSetPathInformationResponse_Parameters()
  546. else:
  547. errorCode = STATUS_SMB_BAD_TID
  548. smbServer.setConnectionData(connId, connData)
  549. return respSetup, respParameters, respData, errorCode
  550. @staticmethod
  551. def setFileInformation(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
  552. connData = smbServer.getConnectionData(connId)
  553. respSetup = ''
  554. respParameters = ''
  555. respData = ''
  556. errorCode = STATUS_SUCCESS
  557. setFileInfoParameters = smb.SMBSetFileInformation_Parameters(parameters)
  558. if connData['ConnectedShares'].has_key(recvPacket['Tid']):
  559. if connData['OpenedFiles'].has_key(setFileInfoParameters['FID']):
  560. fileName = connData['OpenedFiles'][setFileInfoParameters['FID']]['FileName']
  561. informationLevel = setFileInfoParameters['InformationLevel']
  562. if informationLevel == smb.SMB_SET_FILE_DISPOSITION_INFO:
  563. infoRecord = smb.SMBSetFileDispositionInfo(parameters)
  564. if infoRecord['DeletePending'] > 0:
  565. # Mark this file for removal after closed
  566. connData['OpenedFiles'][setFileInfoParameters['FID']]['DeleteOnClose'] = True
  567. respParameters = smb.SMBSetFileInformationResponse_Parameters()
  568. elif informationLevel == smb.SMB_SET_FILE_BASIC_INFO:
  569. infoRecord = smb.SMBSetFileBasicInfo(data)
  570. # Creation time won't be set, the other ones we play with.
  571. atime = infoRecord['LastAccessTime']
  572. if atime == 0:
  573. atime = -1
  574. else:
  575. atime = getUnixTime(atime)
  576. mtime = infoRecord['LastWriteTime']
  577. if mtime == 0:
  578. mtime = -1
  579. else:
  580. mtime = getUnixTime(mtime)
  581. os.utime(fileName,(atime,mtime))
  582. elif informationLevel == smb.SMB_SET_FILE_END_OF_FILE_INFO:
  583. fileHandle = connData['OpenedFiles'][setFileInfoParameters['FID']]['FileHandle']
  584. infoRecord = smb.SMBSetFileEndOfFileInfo(data)
  585. if infoRecord['EndOfFile'] > 0:
  586. os.lseek(fileHandle, infoRecord['EndOfFile']-1, 0)
  587. os.write(fileHandle, '\x00')
  588. else:
  589. smbServer.log('Unknown level for set file info! 0x%x' % setFileInfoParameters['InformationLevel'], logging.ERROR)
  590. # UNSUPPORTED
  591. errorCode = STATUS_NOT_SUPPORTED
  592. else:
  593. errorCode = STATUS_NO_SUCH_FILE
  594. if errorCode == STATUS_SUCCESS:
  595. respParameters = smb.SMBSetFileInformationResponse_Parameters()
  596. else:
  597. errorCode = STATUS_SMB_BAD_TID
  598. smbServer.setConnectionData(connId, connData)
  599. return respSetup, respParameters, respData, errorCode
  600. @staticmethod
  601. def queryFileInformation(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
  602. connData = smbServer.getConnectionData(connId)
  603. respSetup = ''
  604. respParameters = ''
  605. respData = ''
  606. queryFileInfoParameters = smb.SMBQueryFileInformation_Parameters(parameters)
  607. if connData['ConnectedShares'].has_key(recvPacket['Tid']):
  608. if connData['OpenedFiles'].has_key(queryFileInfoParameters['FID']):
  609. fileName = connData['OpenedFiles'][queryFileInfoParameters['FID']]['FileName']
  610. infoRecord, errorCode = queryFileInformation('', fileName, queryFileInfoParameters['InformationLevel'])
  611. if infoRecord is not None:
  612. respParameters = smb.SMBQueryFileInformationResponse_Parameters()
  613. respData = infoRecord
  614. else:
  615. errorCode = STATUS_INVALID_HANDLE
  616. else:
  617. errorCode = STATUS_SMB_BAD_TID
  618. smbServer.setConnectionData(connId, connData)
  619. return respSetup, respParameters, respData, errorCode
  620. @staticmethod
  621. def queryPathInformation(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
  622. connData = smbServer.getConnectionData(connId)
  623. respSetup = ''
  624. respParameters = ''
  625. respData = ''
  626. errorCode = 0
  627. queryPathInfoParameters = smb.SMBQueryPathInformation_Parameters(flags = recvPacket['Flags2'], data = parameters)
  628. if connData['ConnectedShares'].has_key(recvPacket['Tid']):
  629. path = connData['ConnectedShares'][recvPacket['Tid']]['path']
  630. try:
  631. infoRecord, errorCode = queryPathInformation(path, decodeSMBString(recvPacket['Flags2'], queryPathInfoParameters['FileName']), queryPathInfoParameters['InformationLevel'])
  632. except Exception, e:
  633. smbServer.log("queryPathInformation: %s" % e,logging.ERROR)
  634. if infoRecord is not None:
  635. respParameters = smb.SMBQueryPathInformationResponse_Parameters()
  636. respData = infoRecord
  637. else:
  638. errorCode = STATUS_SMB_BAD_TID
  639. smbServer.setConnectionData(connId, connData)
  640. return respSetup, respParameters, respData, errorCode
  641. @staticmethod
  642. def queryFsInformation(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
  643. connData = smbServer.getConnectionData(connId)
  644. errorCode = 0
  645. # Get the Tid associated
  646. if connData['ConnectedShares'].has_key(recvPacket['Tid']):
  647. data = queryFsInformation(connData['ConnectedShares'][recvPacket['Tid']]['path'], '', struct.unpack('<H',parameters)[0])
  648. smbServer.setConnectionData(connId, connData)
  649. return '','', data, errorCode
  650. @staticmethod
  651. def findNext2(connId, smbServer, recvPacket, parameters, data, maxDataCount):
  652. connData = smbServer.getConnectionData(connId)
  653. respSetup = ''
  654. respParameters = ''
  655. respData = ''
  656. errorCode = STATUS_SUCCESS
  657. findNext2Parameters = smb.SMBFindNext2_Parameters(flags = recvPacket['Flags2'], data = parameters)
  658. sid = findNext2Parameters['SID']
  659. if connData['ConnectedShares'].has_key(recvPacket['Tid']):
  660. if connData['SIDs'].has_key(sid):
  661. searchResult = connData['SIDs'][sid]
  662. respParameters = smb.SMBFindNext2Response_Parameters()
  663. endOfSearch = 1
  664. searchCount = 1
  665. totalData = 0
  666. for i in enumerate(searchResult):
  667. data = i[1].getData()
  668. lenData = len(data)
  669. if (totalData+lenData) >= maxDataCount or (i[0]+1) >= findNext2Parameters['SearchCount']:
  670. # We gotta stop here and continue on a find_next2
  671. endOfSearch = 0
  672. connData['SIDs'][sid] = searchResult[i[0]:]
  673. respParameters['LastNameOffset'] = totalData
  674. break
  675. else:
  676. searchCount +=1
  677. respData += data
  678. totalData += lenData
  679. # Have we reached the end of the search or still stuff to send?
  680. if endOfSearch > 0:
  681. # Let's remove the SID from our ConnData
  682. del(connData['SIDs'][sid])
  683. respParameters['EndOfSearch'] = endOfSearch
  684. respParameters['SearchCount'] = searchCount
  685. else:
  686. errorCode = STATUS_INVALID_HANDLE
  687. else:
  688. errorCode = STATUS_SMB_BAD_TID
  689. smbServer.setConnectionData(connId, connData)
  690. return respSetup, respParameters, respData, errorCode
  691. @staticmethod
  692. def findFirst2(connId, smbServer, recvPacket, parameters, data, maxDataCount):
  693. connData = smbServer.getConnectionData(connId)
  694. respSetup = ''
  695. respParameters = ''
  696. respData = ''
  697. findFirst2Parameters = smb.SMBFindFirst2_Parameters( recvPacket['Flags2'], data = parameters)
  698. if connData['ConnectedShares'].has_key(recvPacket['Tid']):
  699. path = connData['ConnectedShares'][recvPacket['Tid']]['path']
  700. searchResult, searchCount, errorCode = findFirst2(path,
  701. decodeSMBString( recvPacket['Flags2'], findFirst2Parameters['FileName'] ),
  702. findFirst2Parameters['InformationLevel'],
  703. findFirst2Parameters['SearchAttributes'] )
  704. respParameters = smb.SMBFindFirst2Response_Parameters()
  705. endOfSearch = 1
  706. sid = 0x80 # default SID
  707. searchCount = 0
  708. totalData = 0
  709. for i in enumerate(searchResult):
  710. #i[1].dump()
  711. data = i[1].getData()
  712. lenData = len(data)
  713. if (totalData+lenData) >= maxDataCount or (i[0]+1) > findFirst2Parameters['SearchCount']:
  714. # We gotta stop here and continue on a find_next2
  715. endOfSearch = 0
  716. # Simple way to generate a fid
  717. if len(connData['SIDs']) == 0:
  718. sid = 1
  719. else:
  720. sid = connData['SIDs'].keys()[-1] + 1
  721. # Store the remaining search results in the ConnData SID
  722. connData['SIDs'][sid] = searchResult[i[0]:]
  723. respParameters['LastNameOffset'] = totalData
  724. break
  725. else:
  726. searchCount +=1
  727. respData += data
  728. padLen = (8-(lenData % 8)) %8
  729. respData += '\xaa'*padLen
  730. totalData += lenData + padLen
  731. respParameters['SID'] = sid
  732. respParameters['EndOfSearch'] = endOfSearch
  733. respParameters['SearchCount'] = searchCount
  734. else:
  735. errorCode = STATUS_SMB_BAD_TID
  736. smbServer.setConnectionData(connId, connData)
  737. return respSetup, respParameters, respData, errorCode
  738. # Here we implement the commands handlers
  739. class SMBCommands:
  740. @staticmethod
  741. def smbTransaction(connId, smbServer, SMBCommand, recvPacket, transCommands):
  742. connData = smbServer.getConnectionData(connId)
  743. respSMBCommand = smb.SMBCommand(recvPacket['Command'])
  744. transParameters= smb.SMBTransaction_Parameters(SMBCommand['Parameters'])
  745. # Do the stuff
  746. if transParameters['ParameterCount'] != transParameters['TotalParameterCount']:
  747. # TODO: Handle partial parameters
  748. raise Exception("Unsupported partial parameters in TRANSACT2!")
  749. else:
  750. transData = smb.SMBTransaction_SData(flags = recvPacket['Flags2'])
  751. # Standard says servers shouldn't trust Parameters and Data comes
  752. # in order, so we have to parse the offsets, ugly
  753. paramCount = transParameters['ParameterCount']
  754. transData['Trans_ParametersLength'] = paramCount
  755. dataCount = transParameters['DataCount']
  756. transData['Trans_DataLength'] = dataCount
  757. transData.fromString(SMBCommand['Data'])
  758. if transParameters['ParameterOffset'] > 0:
  759. paramOffset = transParameters['ParameterOffset'] - 63 - transParameters['SetupLength']
  760. transData['Trans_Parameters'] = SMBCommand['Data'][paramOffset:paramOffset+paramCount]
  761. else:
  762. transData['Trans_Parameters'] = ''
  763. if transParameters['DataOffset'] > 0:
  764. dataOffset = transParameters['DataOffset'] - 63 - transParameters['SetupLength']
  765. transData['Trans_Data'] = SMBCommand['Data'][dataOffset:dataOffset + dataCount]
  766. else:
  767. transData['Trans_Data'] = ''
  768. # Call the handler for this TRANSACTION
  769. if transParameters['SetupCount'] == 0:
  770. # No subcommand, let's play with the Name
  771. command = decodeSMBString(recvPacket['Flags2'],transData['Name'])
  772. else:
  773. command = struct.unpack('<H', transParameters['Setup'][:2])[0]
  774. if transCommands.has_key(command):
  775. # Call the TRANS subcommand
  776. setup = ''
  777. parameters = ''
  778. data = ''
  779. try:
  780. setup, parameters, data, errorCode = transCommands[command](connId,
  781. smbServer,
  782. recvPacket,
  783. transData['Trans_Parameters'],
  784. transData['Trans_Data'],
  785. transParameters['MaxDataCount'])
  786. except Exception, e:
  787. #print 'Transaction: %s' % e,e
  788. smbServer.log('Transaction: (%r,%s)' % (command, e), logging.ERROR)
  789. errorCode = STATUS_ACCESS_DENIED
  790. #raise
  791. if setup == '' and parameters == '' and data == '':
  792. # Something wen't wrong
  793. respParameters = ''
  794. respData = ''
  795. else:
  796. # Build the answer
  797. data = str(data)
  798. remainingData = len(data)
  799. parameters = str(parameters)
  800. remainingParameters = len(parameters)
  801. commands = []
  802. dataDisplacement = 0
  803. while remainingData > 0 or remainingParameters > 0:
  804. respSMBCommand = smb.SMBCommand(recvPacket['Command'])
  805. respParameters = smb.SMBTransactionResponse_Parameters()
  806. respData = smb.SMBTransaction2Response_Data()
  807. respParameters['TotalParameterCount'] = len(parameters)
  808. respParameters['ParameterCount'] = len(parameters)
  809. respData['Trans_ParametersLength'] = len(parameters)
  810. respParameters['TotalDataCount'] = len(data)
  811. respParameters['DataDisplacement'] = dataDisplacement
  812. # TODO: Do the same for parameters
  813. if len(data) > transParameters['MaxDataCount']:
  814. # Answer doesn't fit in this packet
  815. LOG.debug("Lowering answer from %d to %d" % (len(data),transParameters['MaxDataCount']) )
  816. respParameters['DataCount'] = transParameters['MaxDataCount']
  817. else:
  818. respParameters['DataCount'] = len(data)
  819. respData['Trans_DataLength'] = respParameters['DataCount']
  820. respParameters['SetupCount'] = len(setup)
  821. respParameters['Setup'] = setup
  822. # TODO: Make sure we're calculating the pad right
  823. if len(parameters) > 0:
  824. #padLen = 4 - (55 + len(setup)) % 4
  825. padLen = (4 - (55 + len(setup)) % 4 ) % 4
  826. padBytes = '\xFF' * padLen
  827. respData['Pad1'] = padBytes
  828. respParameters['ParameterOffset'] = 55 + len(setup) + padLen
  829. else:
  830. padLen = 0
  831. respParameters['ParameterOffset'] = 0
  832. respData['Pad1'] = ''
  833. if len(data) > 0:
  834. #pad2Len = 4 - (55 + len(setup) + padLen + len(parameters)) % 4
  835. pad2Len = (4 - (55 + len(setup) + padLen + len(parameters)) % 4) % 4
  836. respData['Pad2'] = '\xFF' * pad2Len
  837. respParameters['DataOffset'] = 55 + len(setup) + padLen + len(parameters) + pad2Len
  838. else:
  839. respParameters['DataOffset'] = 0
  840. respData['Pad2'] = ''
  841. respData['Trans_Parameters'] = parameters[:respParameters['ParameterCount']]
  842. respData['Trans_Data'] = data[:respParameters['DataCount']]
  843. respSMBCommand['Parameters'] = respParameters
  844. respSMBCommand['Data'] = respData
  845. data = data[respParameters['DataCount']:]
  846. remainingData -= respParameters['DataCount']
  847. dataDisplacement += respParameters['DataCount'] + 1
  848. parameters = parameters[respParameters['ParameterCount']:]
  849. remainingParameters -= respParameters['ParameterCount']
  850. commands.append(respSMBCommand)
  851. smbServer.setConnectionData(connId, connData)
  852. return commands, None, errorCode
  853. else:
  854. smbServer.log("Unsupported Transact command %r" % command, logging.ERROR)
  855. respParameters = ''
  856. respData = ''
  857. errorCode = STATUS_NOT_IMPLEMENTED
  858. respSMBCommand['Parameters'] = respParameters
  859. respSMBCommand['Data'] = respData
  860. smbServer.setConnectionData(connId, connData)
  861. return [respSMBCommand], None, errorCode
  862. @staticmethod
  863. def smbNTTransact(connId, smbServer, SMBCommand, recvPacket, transCommands):
  864. connData = smbServer.getConnectionData(connId)
  865. respSMBCommand = smb.SMBCommand(recvPacket['Command'])
  866. NTTransParameters= smb.SMBNTTransaction_Parameters(SMBCommand['Parameters'])
  867. # Do the stuff
  868. if NTTransParameters['ParameterCount'] != NTTransParameters['TotalParameterCount']:
  869. # TODO: Handle partial parameters
  870. raise Exception("Unsupported partial parameters in NTTrans!")
  871. else:
  872. NTTransData = smb.SMBNTTransaction_Data()
  873. # Standard says servers shouldn't trust Parameters and Data comes
  874. # in order, so we have to parse the offsets, ugly
  875. paramCount = NTTransParameters['ParameterCount']
  876. NTTransData['NT_Trans_ParametersLength'] = paramCount
  877. dataCount = NTTransParameters['DataCount']
  878. NTTransData['NT_Trans_DataLength'] = dataCount
  879. if NTTransParameters['ParameterOffset'] > 0:
  880. paramOffset = NTTransParameters['ParameterOffset'] - 73 - NTTransParameters['SetupLength']
  881. NTTransData['NT_Trans_Parameters'] = SMBCommand['Data'][paramOffset:paramOffset+paramCount]
  882. else:
  883. NTTransData['NT_Trans_Parameters'] = ''
  884. if NTTransParameters['DataOffset'] > 0:
  885. dataOffset = NTTransParameters['DataOffset'] - 73 - NTTransParameters['SetupLength']
  886. NTTransData['NT_Trans_Data'] = SMBCommand['Data'][dataOffset:dataOffset + dataCount]
  887. else:
  888. NTTransData['NT_Trans_Data'] = ''
  889. # Call the handler for this TRANSACTION
  890. command = NTTransParameters['Function']
  891. if transCommands.has_key(command):
  892. # Call the NT TRANS subcommand
  893. setup = ''
  894. parameters = ''
  895. data = ''
  896. try:
  897. setup, parameters, data, errorCode = transCommands[command](connId,
  898. smbServer,
  899. recvPacket,
  900. NTTransData['NT_Trans_Parameters'],
  901. NTTransData['NT_Trans_Data'],
  902. NTTransParameters['MaxDataCount'])
  903. except Exception, e:
  904. smbServer.log('NTTransaction: (0x%x,%s)' % (command, e), logging.ERROR)
  905. errorCode = STATUS_ACCESS_DENIED
  906. #raise
  907. if setup == '' and parameters == '' and data == '':
  908. # Something wen't wrong
  909. respParameters = ''
  910. respData = ''
  911. if errorCode == STATUS_SUCCESS:
  912. errorCode = STATUS_ACCESS_DENIED
  913. else:
  914. # Build the answer
  915. data = str(data)
  916. remainingData = len(data)
  917. parameters = str(parameters)
  918. remainingParameters = len(parameters)
  919. commands = []
  920. dataDisplacement = 0
  921. while remainingData > 0 or remainingParameters > 0:
  922. respSMBCommand = smb.SMBCommand(recvPacket['Command'])
  923. respParameters = smb.SMBNTTransactionResponse_Parameters()
  924. respData = smb.SMBNTTransactionResponse_Data()
  925. respParameters['TotalParameterCount'] = len(parameters)
  926. respParameters['ParameterCount'] = len(parameters)
  927. respData['Trans_ParametersLength'] = len(parameters)
  928. respParameters['TotalDataCount'] = len(data)
  929. respParameters['DataDisplacement'] = dataDisplacement
  930. # TODO: Do the same for parameters
  931. if len(data) > NTTransParameters['MaxDataCount']:
  932. # Answer doesn't fit in this packet
  933. LOG.debug("Lowering answer from %d to %d" % (len(data),NTTransParameters['MaxDataCount']) )
  934. respParameters['DataCount'] = NTTransParameters['MaxDataCount']
  935. else:
  936. respParameters['DataCount'] = len(data)
  937. respData['NT_Trans_DataLength'] = respParameters['DataCount']
  938. respParameters['SetupCount'] = len(setup)
  939. respParameters['Setup'] = setup
  940. # TODO: Make sure we're calculating the pad right
  941. if len(parameters) > 0:
  942. #padLen = 4 - (71 + len(setup)) % 4
  943. padLen = (4 - (73 + len(setup)) % 4 ) % 4
  944. padBytes = '\xFF' * padLen
  945. respData['Pad1'] = padBytes
  946. respParameters['ParameterOffset'] = 73 + len(setup) + padLen
  947. else:
  948. padLen = 0
  949. respParameters['ParameterOffset'] = 0
  950. respData['Pad1'] = ''
  951. if len(data) > 0:
  952. #pad2Len = 4 - (71 + len(setup) + padLen + len(parameters)) % 4
  953. pad2Len = (4 - (73 + len(setup) + padLen + len(parameters)) % 4) % 4
  954. respData['Pad2'] = '\xFF' * pad2Len
  955. respParameters['DataOffset'] = 73 + len(setup) + padLen + len(parameters) + pad2Len
  956. else:
  957. respParameters['DataOffset'] = 0
  958. respData['Pad2'] = ''
  959. respData['NT_Trans_Parameters'] = parameters[:respParameters['ParameterCount']]
  960. respData['NT_Trans_Data'] = data[:respParameters['DataCount']]
  961. respSMBCommand['Parameters'] = respParameters
  962. respSMBCommand['Data'] = respData
  963. data = data[respParameters['DataCount']:]
  964. remainingData -= respParameters['DataCount']
  965. dataDisplacement += respParameters['DataCount'] + 1
  966. parameters = parameters[respParameters['ParameterCount']:]
  967. remainingParameters -= respParameters['ParameterCount']
  968. commands.append(respSMBCommand)
  969. smbServer.setConnectionData(connId, connData)
  970. return commands, None, errorCode
  971. else:
  972. #smbServer.log("Unsupported NTTransact command 0x%x" % command, logging.ERROR)
  973. respParameters = ''
  974. respData = ''
  975. errorCode = STATUS_NOT_IMPLEMENTED
  976. respSMBCommand['Parameters'] = respParameters
  977. respSMBCommand['Data'] = respData
  978. smbServer.setConnectionData(connId, connData)
  979. return [respSMBCommand], None, errorCode
  980. @staticmethod
  981. def smbTransaction2(connId, smbServer, SMBCommand, recvPacket, transCommands):
  982. connData = smbServer.getConnectionData(connId)
  983. respSMBCommand = smb.SMBCommand(recvPacket['Command'])
  984. trans2Parameters= smb.SMBTransaction2_Parameters(SMBCommand['Parameters'])
  985. # Do the stuff
  986. if trans2Parameters['ParameterCount'] != trans2Parameters['TotalParameterCount']:
  987. # TODO: Handle partial parameters
  988. #print "Unsupported partial parameters in TRANSACT2!"
  989. raise Exception("Unsupported partial parameters in TRANSACT2!")
  990. else:
  991. trans2Data = smb.SMBTransaction2_Data()
  992. # Standard says servers shouldn't trust Parameters and Data comes
  993. # in order, so we have to parse the offsets, ugly
  994. paramCount = trans2Parameters['ParameterCount']
  995. trans2Data['Trans_ParametersLength'] = paramCount
  996. dataCount = trans2Parameters['DataCount']
  997. trans2Data['Trans_DataLength'] = dataCount
  998. if trans2Parameters['ParameterOffset'] > 0:
  999. paramOffset = trans2Parameters['ParameterOffset'] - 63 - trans2Parameters['SetupLength']
  1000. trans2Data['Trans_Parameters'] = SMBCommand['Data'][paramOffset:paramOffset+paramCount]
  1001. else:
  1002. trans2Data['Trans_Parameters'] = ''
  1003. if trans2Parameters['DataOffset'] > 0:
  1004. dataOffset = trans2Parameters['DataOffset'] - 63 - trans2Parameters['SetupLength']
  1005. trans2Data['Trans_Data'] = SMBCommand['Data'][dataOffset:dataOffset + dataCount]
  1006. else:
  1007. trans2Data['Trans_Data'] = ''
  1008. # Call the handler for this TRANSACTION
  1009. command = struct.unpack('<H', trans2Parameters['Setup'])[0]
  1010. if transCommands.has_key(command):
  1011. # Call the TRANS2 subcommand
  1012. try:
  1013. setup, parameters, data, errorCode = transCommands[command](connId,
  1014. smbServer,
  1015. recvPacket,
  1016. trans2Data['Trans_Parameters'],
  1017. trans2Data['Trans_Data'],
  1018. trans2Parameters['MaxDataCount'])
  1019. except Exception, e:
  1020. smbServer.log('Transaction2: (0x%x,%s)' % (command, e), logging.ERROR)
  1021. #import traceback
  1022. #traceback.print_exc()
  1023. raise
  1024. if setup == '' and parameters == '' and data == '':
  1025. # Something wen't wrong
  1026. respParameters = ''
  1027. respData = ''
  1028. else:
  1029. # Build the answer
  1030. data = str(data)
  1031. remainingData = len(data)
  1032. parameters = str(parameters)
  1033. remainingParameters = len(parameters)
  1034. commands = []
  1035. dataDisplacement = 0
  1036. while remainingData > 0 or remainingParameters > 0:
  1037. respSMBCommand = smb.SMBCommand(recvPacket['Command'])
  1038. respParameters = smb.SMBTransaction2Response_Parameters()
  1039. respData = smb.SMBTransaction2Response_Data()
  1040. respParameters['TotalParameterCount'] = len(parameters)
  1041. respParameters['ParameterCount'] = len(parameters)
  1042. respData['Trans_ParametersLength'] = len(parameters)
  1043. respParameters['TotalDataCount'] = len(data)
  1044. respParameters['DataDisplacement'] = dataDisplacement
  1045. # TODO: Do the same for parameters
  1046. if len(data) > trans2Parameters['MaxDataCount']:
  1047. # Answer doesn't fit in this packet
  1048. LOG.debug("Lowering answer from %d to %d" % (len(data),trans2Parameters['MaxDataCount']) )
  1049. respParameters['DataCount'] = trans2Parameters['MaxDataCount']
  1050. else:
  1051. respParameters['DataCount'] = len(data)
  1052. respData['Trans_DataLength'] = respParameters['DataCount']
  1053. respParameters['SetupCount'] = len(setup)
  1054. respParameters['Setup'] = setup
  1055. # TODO: Make sure we're calculating the pad right
  1056. if len(parameters) > 0:
  1057. #padLen = 4 - (55 + len(setup)) % 4
  1058. padLen = (4 - (55 + len(setup)) % 4 ) % 4
  1059. padBytes = '\xFF' * padLen
  1060. respData['Pad1'] = padBytes
  1061. respParameters['ParameterOffset'] = 55 + len(setup) + padLen
  1062. else:
  1063. padLen = 0
  1064. respParameters['ParameterOffset'] = 0
  1065. respData['Pad1'] = ''
  1066. if len(data) > 0:
  1067. #pad2Len = 4 - (55 + len(setup) + padLen + len(parameters)) % 4
  1068. pad2Len = (4 - (55 + len(setup) + padLen + len(parameters)) % 4) % 4
  1069. respData['Pad2'] = '\xFF' * pad2Len
  1070. respParameters['DataOffset'] = 55 + len(setup) + padLen + len(parameters) + pad2Len
  1071. else:
  1072. respParameters['DataOffset'] = 0
  1073. respData['Pad2'] = ''
  1074. respData['Trans_Parameters'] = parameters[:respParameters['ParameterCount']]
  1075. respData['Trans_Data'] = data[:respParameters['DataCount']]
  1076. respSMBCommand['Parameters'] = respParameters
  1077. respSMBCommand['Data'] = respData
  1078. data = data[respParameters['DataCount']:]
  1079. remainingData -= respParameters['DataCount']
  1080. dataDisplacement += respParameters['DataCount'] + 1
  1081. parameters = parameters[respParameters['ParameterCount']:]
  1082. remainingParameters -= respParameters['ParameterCount']
  1083. commands.append(respSMBCommand)
  1084. smbServer.setConnectionData(connId, connData)
  1085. return commands, None, errorCode
  1086. else:
  1087. smbServer.log("Unsupported Transact/2 command 0x%x" % command, logging.ERROR)
  1088. respParameters = ''
  1089. respData = ''
  1090. errorCode = STATUS_NOT_IMPLEMENTED
  1091. respSMBCommand['Parameters'] = respParameters
  1092. respSMBCommand['Data'] = respData
  1093. smbServer.setConnectionData(connId, connData)
  1094. return [respSMBCommand], None, errorCode
  1095. @staticmethod
  1096. def smbComLockingAndX(connId, smbServer, SMBCommand, recvPacket):
  1097. connData = smbServer.getConnectionData(connId)
  1098. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_LOCKING_ANDX)
  1099. respParameters = ''
  1100. respData = ''
  1101. # I'm actually doing nothing.. just make MacOS happy ;)
  1102. errorCode = STATUS_SUCCESS
  1103. respSMBCommand['Parameters'] = respParameters
  1104. respSMBCommand['Data'] = respData
  1105. smbServer.setConnectionData(connId, connData)
  1106. return [respSMBCommand], None, errorCode
  1107. @staticmethod
  1108. def smbComClose(connId, smbServer, SMBCommand, recvPacket):
  1109. connData = smbServer.getConnectionData(connId)
  1110. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_CLOSE)
  1111. respParameters = ''
  1112. respData = ''
  1113. comClose = smb.SMBClose_Parameters(SMBCommand['Parameters'])
  1114. if connData['OpenedFiles'].has_key(comClose['FID']):
  1115. errorCode = STATUS_SUCCESS
  1116. fileHandle = connData['OpenedFiles'][comClose['FID']]['FileHandle']
  1117. try:
  1118. if fileHandle == PIPE_FILE_DESCRIPTOR:
  1119. connData['OpenedFiles'][comClose['FID']]['Socket'].close()
  1120. elif fileHandle != VOID_FILE_DESCRIPTOR:
  1121. os.close(fileHandle)
  1122. except Exception, e:
  1123. smbServer.log("comClose %s" % e, logging.ERROR)
  1124. errorCode = STATUS_ACCESS_DENIED
  1125. else:
  1126. # Check if the file was marked for removal
  1127. if connData['OpenedFiles'][comClose['FID']]['DeleteOnClose'] is True:
  1128. try:
  1129. os.remove(connData['OpenedFiles'][comClose['FID']]['FileName'])
  1130. except Exception, e:
  1131. smbServer.log("comClose %s" % e, logging.ERROR)
  1132. errorCode = STATUS_ACCESS_DENIED
  1133. del(connData['OpenedFiles'][comClose['FID']])
  1134. else:
  1135. errorCode = STATUS_INVALID_HANDLE
  1136. if errorCode > 0:
  1137. respParameters = ''
  1138. respData = ''
  1139. respSMBCommand['Parameters'] = respParameters
  1140. respSMBCommand['Data'] = respData
  1141. smbServer.setConnectionData(connId, connData)
  1142. return [respSMBCommand], None, errorCode
  1143. @staticmethod
  1144. def smbComWrite(connId, smbServer, SMBCommand, recvPacket):
  1145. connData = smbServer.getConnectionData(connId)
  1146. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_WRITE)
  1147. respParameters = smb.SMBWriteResponse_Parameters()
  1148. respData = ''
  1149. comWriteParameters = smb.SMBWrite_Parameters(SMBCommand['Parameters'])
  1150. comWriteData = smb.SMBWrite_Data(SMBCommand['Data'])
  1151. if connData['OpenedFiles'].has_key(comWriteParameters['Fid']):
  1152. fileHandle = connData['OpenedFiles'][comWriteParameters['Fid']]['FileHandle']
  1153. errorCode = STATUS_SUCCESS
  1154. try:
  1155. if fileHandle != PIPE_FILE_DESCRIPTOR:
  1156. # TODO: Handle big size files
  1157. # If we're trying to write past the file end we just skip the write call (Vista does this)
  1158. if os.lseek(fileHandle, 0, 2) >= comWriteParameters['Offset']:
  1159. os.lseek(fileHandle,comWriteParameters['Offset'],0)
  1160. os.write(fileHandle,comWriteData['Data'])
  1161. else:
  1162. sock = connData['OpenedFiles'][comWriteParameters['Fid']]['Socket']
  1163. sock.send(comWriteData['Data'])
  1164. respParameters['Count'] = comWriteParameters['Count']
  1165. except Exception, e:
  1166. smbServer.log('smbComWrite: %s' % e, logging.ERROR)
  1167. errorCode = STATUS_ACCESS_DENIED
  1168. else:
  1169. errorCode = STATUS_INVALID_HANDLE
  1170. if errorCode > 0:
  1171. respParameters = ''
  1172. respData = ''
  1173. respSMBCommand['Parameters'] = respParameters
  1174. respSMBCommand['Data'] = respData
  1175. smbServer.setConnectionData(connId, connData)
  1176. return [respSMBCommand], None, errorCode
  1177. @staticmethod
  1178. def smbComFlush(connId, smbServer, SMBCommand,recvPacket ):
  1179. connData = smbServer.getConnectionData(connId)
  1180. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_FLUSH)
  1181. respParameters = ''
  1182. respData = ''
  1183. comFlush = smb.SMBFlush_Parameters(SMBCommand['Parameters'])
  1184. if connData['OpenedFiles'].has_key(comFlush['FID']):
  1185. errorCode = STATUS_SUCCESS
  1186. fileHandle = connData['OpenedFiles'][comFlush['FID']]['FileHandle']
  1187. try:
  1188. os.fsync(fileHandle)
  1189. except Exception, e:
  1190. smbServer.log("comFlush %s" % e, logging.ERROR)
  1191. errorCode = STATUS_ACCESS_DENIED
  1192. else:
  1193. errorCode = STATUS_INVALID_HANDLE
  1194. if errorCode > 0:
  1195. respParameters = ''
  1196. respData = ''
  1197. respSMBCommand['Parameters'] = respParameters
  1198. respSMBCommand['Data'] = respData
  1199. smbServer.setConnectionData(connId, connData)
  1200. return [respSMBCommand], None, errorCode
  1201. @staticmethod
  1202. def smbComCreateDirectory(connId, smbServer, SMBCommand,recvPacket ):
  1203. connData = smbServer.getConnectionData(connId)
  1204. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_CREATE_DIRECTORY)
  1205. respParameters = ''
  1206. respData = ''
  1207. comCreateDirectoryData= smb.SMBCreateDirectory_Data(flags = recvPacket['Flags2'], data = SMBCommand['Data'])
  1208. # Get the Tid associated
  1209. if connData['ConnectedShares'].has_key(recvPacket['Tid']):
  1210. errorCode = STATUS_SUCCESS
  1211. path = connData['ConnectedShares'][recvPacket['Tid']]['path']
  1212. fileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],comCreateDirectoryData['DirectoryName']).replace('\\','/'))
  1213. if len(fileName) > 0:
  1214. if fileName[0] == '/' or fileName[0] == '\\':
  1215. # strip leading '/'
  1216. fileName = fileName[1:]
  1217. pathName = os.path.join(path,fileName)
  1218. if os.path.exists(pathName):
  1219. errorCode = STATUS_OBJECT_NAME_COLLISION
  1220. # TODO: More checks here in the future.. Specially when we support
  1221. # user access
  1222. else:
  1223. try:
  1224. os.mkdir(pathName)
  1225. except Exception, e:
  1226. smbServer.log("smbComCreateDirectory: %s" % e, logging.ERROR)
  1227. errorCode = STATUS_ACCESS_DENIED
  1228. else:
  1229. errorCode = STATUS_SMB_BAD_TID
  1230. if errorCode > 0:
  1231. respParameters = ''
  1232. respData = ''
  1233. respSMBCommand['Parameters'] = respParameters
  1234. respSMBCommand['Data'] = respData
  1235. smbServer.setConnectionData(connId, connData)
  1236. return [respSMBCommand], None, errorCode
  1237. @staticmethod
  1238. def smbComRename(connId, smbServer, SMBCommand, recvPacket ):
  1239. connData = smbServer.getConnectionData(connId)
  1240. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_RENAME)
  1241. respParameters = ''
  1242. respData = ''
  1243. comRenameData = smb.SMBRename_Data(flags = recvPacket['Flags2'], data = SMBCommand['Data'])
  1244. # Get the Tid associated
  1245. if connData['ConnectedShares'].has_key(recvPacket['Tid']):
  1246. errorCode = STATUS_SUCCESS
  1247. path = connData['ConnectedShares'][recvPacket['Tid']]['path']
  1248. oldFileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],comRenameData['OldFileName']).replace('\\','/'))
  1249. newFileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],comRenameData['NewFileName']).replace('\\','/'))
  1250. if len(oldFileName) > 0 and (oldFileName[0] == '/' or oldFileName[0] == '\\'):
  1251. # strip leading '/'
  1252. oldFileName = oldFileName[1:]
  1253. oldPathName = os.path.join(path,oldFileName)
  1254. if len(newFileName) > 0 and (newFileName[0] == '/' or newFileName[0] == '\\'):
  1255. # strip leading '/'
  1256. newFileName = newFileName[1:]
  1257. newPathName = os.path.join(path,newFileName)
  1258. if os.path.exists(oldPathName) is not True:
  1259. errorCode = STATUS_NO_SUCH_FILE
  1260. # TODO: More checks here in the future.. Specially when we support
  1261. # user access
  1262. else:
  1263. try:
  1264. os.rename(oldPathName,newPathName)
  1265. except OSError, e:
  1266. smbServer.log("smbComRename: %s" % e, logging.ERROR)
  1267. errorCode = STATUS_ACCESS_DENIED
  1268. else:
  1269. errorCode = STATUS_SMB_BAD_TID
  1270. if errorCode > 0:
  1271. respParameters = ''
  1272. respData = ''
  1273. respSMBCommand['Parameters'] = respParameters
  1274. respSMBCommand['Data'] = respData
  1275. smbServer.setConnectionData(connId, connData)
  1276. return [respSMBCommand], None, errorCode
  1277. @staticmethod
  1278. def smbComDelete(connId, smbServer, SMBCommand, recvPacket ):
  1279. connData = smbServer.getConnectionData(connId)
  1280. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_DELETE)
  1281. respParameters = ''
  1282. respData = ''
  1283. comDeleteData = smb.SMBDelete_Data(flags = recvPacket['Flags2'], data = SMBCommand['Data'])
  1284. # Get the Tid associated
  1285. if connData['ConnectedShares'].has_key(recvPacket['Tid']):
  1286. errorCode = STATUS_SUCCESS
  1287. path = connData['ConnectedShares'][recvPacket['Tid']]['path']
  1288. fileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],comDeleteData['FileName']).replace('\\','/'))
  1289. if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
  1290. # strip leading '/'
  1291. fileName = fileName[1:]
  1292. pathName = os.path.join(path,fileName)
  1293. if os.path.exists(pathName) is not True:
  1294. errorCode = STATUS_NO_SUCH_FILE
  1295. # TODO: More checks here in the future.. Specially when we support
  1296. # user access
  1297. else:
  1298. try:
  1299. os.remove(pathName)
  1300. except OSError, e:
  1301. smbServer.log("smbComDelete: %s" % e, logging.ERROR)
  1302. errorCode = STATUS_ACCESS_DENIED
  1303. else:
  1304. errorCode = STATUS_SMB_BAD_TID
  1305. if errorCode > 0:
  1306. respParameters = ''
  1307. respData = ''
  1308. respSMBCommand['Parameters'] = respParameters
  1309. respSMBCommand['Data'] = respData
  1310. smbServer.setConnectionData(connId, connData)
  1311. return [respSMBCommand], None, errorCode
  1312. @staticmethod
  1313. def smbComDeleteDirectory(connId, smbServer, SMBCommand, recvPacket ):
  1314. connData = smbServer.getConnectionData(connId)
  1315. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_DELETE_DIRECTORY)
  1316. respParameters = ''
  1317. respData = ''
  1318. comDeleteDirectoryData= smb.SMBDeleteDirectory_Data(flags = recvPacket['Flags2'], data = SMBCommand['Data'])
  1319. # Get the Tid associated
  1320. if connData['ConnectedShares'].has_key(recvPacket['Tid']):
  1321. errorCode = STATUS_SUCCESS
  1322. path = connData['ConnectedShares'][recvPacket['Tid']]['path']
  1323. fileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],comDeleteDirectoryData['DirectoryName']).replace('\\','/'))
  1324. if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
  1325. # strip leading '/'
  1326. fileName = fileName[1:]
  1327. pathName = os.path.join(path,fileName)
  1328. if os.path.exists(pathName) is not True:
  1329. errorCode = STATUS_NO_SUCH_FILE
  1330. # TODO: More checks here in the future.. Specially when we support
  1331. # user access
  1332. else:
  1333. try:
  1334. os.rmdir(pathName)
  1335. except OSError, e:
  1336. smbServer.log("smbComDeleteDirectory: %s" % e,logging.ERROR)
  1337. if e.errno == errno.ENOTEMPTY:
  1338. errorCode = STATUS_DIRECTORY_NOT_EMPTY
  1339. else:
  1340. errorCode = STATUS_ACCESS_DENIED
  1341. else:
  1342. errorCode = STATUS_SMB_BAD_TID
  1343. if errorCode > 0:
  1344. respParameters = ''
  1345. respData = ''
  1346. respSMBCommand['Parameters'] = respParameters
  1347. respSMBCommand['Data'] = respData
  1348. smbServer.setConnectionData(connId, connData)
  1349. return [respSMBCommand], None, errorCode
  1350. @staticmethod
  1351. def smbComWriteAndX(connId, smbServer, SMBCommand, recvPacket):
  1352. connData = smbServer.getConnectionData(connId)
  1353. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_WRITE_ANDX)
  1354. respParameters = smb.SMBWriteAndXResponse_Parameters()
  1355. respData = ''
  1356. if SMBCommand['WordCount'] == 0x0C:
  1357. writeAndX = smb.SMBWriteAndX_Parameters_Short(SMBCommand['Parameters'])
  1358. writeAndXData = smb.SMBWriteAndX_Data_Short()
  1359. else:
  1360. writeAndX = smb.SMBWriteAndX_Parameters(SMBCommand['Parameters'])
  1361. writeAndXData = smb.SMBWriteAndX_Data()
  1362. writeAndXData['DataLength'] = writeAndX['DataLength']
  1363. writeAndXData['DataOffset'] = writeAndX['DataOffset']
  1364. writeAndXData.fromString(SMBCommand['Data'])
  1365. if connData['OpenedFiles'].has_key(writeAndX['Fid']):
  1366. fileHandle = connData['OpenedFiles'][writeAndX['Fid']]['FileHandle']
  1367. errorCode = STATUS_SUCCESS
  1368. try:
  1369. if fileHandle != PIPE_FILE_DESCRIPTOR:
  1370. offset = writeAndX['Offset']
  1371. if writeAndX.fields.has_key('HighOffset'):
  1372. offset += (writeAndX['HighOffset'] << 32)
  1373. # If we're trying to write past the file end we just skip the write call (Vista does this)
  1374. if os.lseek(fileHandle, 0, 2) >= offset:
  1375. os.lseek(fileHandle,offset,0)
  1376. os.write(fileHandle,writeAndXData['Data'])
  1377. else:
  1378. sock = connData['OpenedFiles'][writeAndX['Fid']]['Socket']
  1379. sock.send(writeAndXData['Data'])
  1380. respParameters['Count'] = writeAndX['DataLength']
  1381. respParameters['Available']= 0xff
  1382. except Exception, e:
  1383. smbServer.log('smbComWriteAndx: %s' % e, logging.ERROR)
  1384. errorCode = STATUS_ACCESS_DENIED
  1385. else:
  1386. errorCode = STATUS_INVALID_HANDLE
  1387. if errorCode > 0:
  1388. respParameters = ''
  1389. respData = ''
  1390. respSMBCommand['Parameters'] = respParameters
  1391. respSMBCommand['Data'] = respData
  1392. smbServer.setConnectionData(connId, connData)
  1393. return [respSMBCommand], None, errorCode
  1394. @staticmethod
  1395. def smbComRead(connId, smbServer, SMBCommand, recvPacket):
  1396. connData = smbServer.getConnectionData(connId)
  1397. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_READ)
  1398. respParameters = smb.SMBReadResponse_Parameters()
  1399. respData = smb.SMBReadResponse_Data()
  1400. comReadParameters = smb.SMBRead_Parameters(SMBCommand['Parameters'])
  1401. if connData['OpenedFiles'].has_key(comReadParameters['Fid']):
  1402. fileHandle = connData['OpenedFiles'][comReadParameters['Fid']]['FileHandle']
  1403. errorCode = STATUS_SUCCESS
  1404. try:
  1405. if fileHandle != PIPE_FILE_DESCRIPTOR:
  1406. # TODO: Handle big size files
  1407. os.lseek(fileHandle,comReadParameters['Offset'],0)
  1408. content = os.read(fileHandle,comReadParameters['Count'])
  1409. else:
  1410. sock = connData['OpenedFiles'][comReadParameters['Fid']]['Socket']
  1411. content = sock.recv(comReadParameters['Count'])
  1412. respParameters['Count'] = len(content)
  1413. respData['DataLength'] = len(content)
  1414. respData['Data'] = content
  1415. except Exception, e:
  1416. smbServer.log('smbComRead: %s ' % e, logging.ERROR)
  1417. errorCode = STATUS_ACCESS_DENIED
  1418. else:
  1419. errorCode = STATUS_INVALID_HANDLE
  1420. if errorCode > 0:
  1421. respParameters = ''
  1422. respData = ''
  1423. respSMBCommand['Parameters'] = respParameters
  1424. respSMBCommand['Data'] = respData
  1425. smbServer.setConnectionData(connId, connData)
  1426. return [respSMBCommand], None, errorCode
  1427. @staticmethod
  1428. def smbComReadAndX(connId, smbServer, SMBCommand, recvPacket):
  1429. connData = smbServer.getConnectionData(connId)
  1430. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_READ_ANDX)
  1431. respParameters = smb.SMBReadAndXResponse_Parameters()
  1432. respData = ''
  1433. if SMBCommand['WordCount'] == 0x0A:
  1434. readAndX = smb.SMBReadAndX_Parameters2(SMBCommand['Parameters'])
  1435. else:
  1436. readAndX = smb.SMBReadAndX_Parameters(SMBCommand['Parameters'])
  1437. if connData['OpenedFiles'].has_key(readAndX['Fid']):
  1438. fileHandle = connData['OpenedFiles'][readAndX['Fid']]['FileHandle']
  1439. errorCode = 0
  1440. try:
  1441. if fileHandle != PIPE_FILE_DESCRIPTOR:
  1442. offset = readAndX['Offset']
  1443. if readAndX.fields.has_key('HighOffset'):
  1444. offset += (readAndX['HighOffset'] << 32)
  1445. os.lseek(fileHandle,offset,0)
  1446. content = os.read(fileHandle,readAndX['MaxCount'])
  1447. else:
  1448. sock = connData['OpenedFiles'][readAndX['Fid']]['Socket']
  1449. content = sock.recv(readAndX['MaxCount'])
  1450. respParameters['Remaining'] = 0xffff
  1451. respParameters['DataCount'] = len(content)
  1452. respParameters['DataOffset'] = 59
  1453. respParameters['DataCount_Hi'] = 0
  1454. respData = content
  1455. except Exception, e:
  1456. smbServer.log('smbComReadAndX: %s ' % e, logging.ERROR)
  1457. errorCode = STATUS_ACCESS_DENIED
  1458. else:
  1459. errorCode = STATUS_INVALID_HANDLE
  1460. if errorCode > 0:
  1461. respParameters = ''
  1462. respData = ''
  1463. respSMBCommand['Parameters'] = respParameters
  1464. respSMBCommand['Data'] = respData
  1465. smbServer.setConnectionData(connId, connData)
  1466. return [respSMBCommand], None, errorCode
  1467. @staticmethod
  1468. def smbQueryInformation(connId, smbServer, SMBCommand, recvPacket):
  1469. connData = smbServer.getConnectionData(connId)
  1470. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_QUERY_INFORMATION)
  1471. respParameters = smb.SMBQueryInformationResponse_Parameters()
  1472. respData = ''
  1473. queryInformation= smb.SMBQueryInformation_Data(flags = recvPacket['Flags2'], data = SMBCommand['Data'])
  1474. # Get the Tid associated
  1475. if connData['ConnectedShares'].has_key(recvPacket['Tid']):
  1476. fileSize, lastWriteTime, fileAttributes = queryFsInformation(
  1477. connData['ConnectedShares'][recvPacket['Tid']]['path'],
  1478. decodeSMBString(recvPacket['Flags2'],queryInformation['FileName']))
  1479. respParameters['FileSize'] = fileSize
  1480. respParameters['LastWriteTime'] = lastWriteTime
  1481. respParameters['FileAttributes'] = fileAttributes
  1482. errorCode = STATUS_SUCCESS
  1483. else:
  1484. # STATUS_SMB_BAD_TID
  1485. errorCode = STATUS_SMB_BAD_TID
  1486. respParameters = ''
  1487. respData = ''
  1488. respSMBCommand['Parameters'] = respParameters
  1489. respSMBCommand['Data'] = respData
  1490. smbServer.setConnectionData(connId, connData)
  1491. return [respSMBCommand], None, errorCode
  1492. @staticmethod
  1493. def smbQueryInformationDisk(connId, smbServer, SMBCommand, recvPacket):
  1494. connData = smbServer.getConnectionData(connId)
  1495. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_QUERY_INFORMATION_DISK)
  1496. respParameters = smb.SMBQueryInformationDiskResponse_Parameters()
  1497. respData = ''
  1498. # Get the Tid associated
  1499. if connData['ConnectedShares'].has_key(recvPacket['Tid']):
  1500. totalUnits, freeUnits = queryDiskInformation(
  1501. connData['ConnectedShares'][recvPacket['Tid']]['path'])
  1502. respParameters['TotalUnits'] = totalUnits
  1503. respParameters['BlocksPerUnit'] = 1
  1504. respParameters['BlockSize'] = 1
  1505. respParameters['FreeUnits'] = freeUnits
  1506. errorCode = STATUS_SUCCESS
  1507. else:
  1508. # STATUS_SMB_BAD_TID
  1509. respData = ''
  1510. respParameters = ''
  1511. errorCode = STATUS_SMB_BAD_TID
  1512. respSMBCommand['Parameters'] = respParameters
  1513. respSMBCommand['Data'] = respData
  1514. smbServer.setConnectionData(connId, connData)
  1515. return [respSMBCommand], None, errorCode
  1516. @staticmethod
  1517. def smbComEcho(connId, smbServer, SMBCommand, recvPacket):
  1518. connData = smbServer.getConnectionData(connId)
  1519. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_ECHO)
  1520. respParameters = smb.SMBEchoResponse_Parameters()
  1521. respData = smb.SMBEchoResponse_Data()
  1522. echoData = smb.SMBEcho_Data(SMBCommand['Data'])
  1523. respParameters['SequenceNumber'] = 1
  1524. respData['Data'] = echoData['Data']
  1525. respSMBCommand['Parameters'] = respParameters
  1526. respSMBCommand['Data'] = respData
  1527. errorCode = STATUS_SUCCESS
  1528. smbServer.setConnectionData(connId, connData)
  1529. return [respSMBCommand], None, errorCode
  1530. @staticmethod
  1531. def smbComTreeDisconnect(connId, smbServer, SMBCommand, recvPacket):
  1532. connData = smbServer.getConnectionData(connId)
  1533. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_TREE_DISCONNECT)
  1534. # Check if the Tid matches the Tid trying to disconnect
  1535. respParameters = ''
  1536. respData = ''
  1537. if connData['ConnectedShares'].has_key(recvPacket['Tid']):
  1538. smbServer.log("Disconnecting Share(%d:%s)" % (recvPacket['Tid'],connData['ConnectedShares'][recvPacket['Tid']]['shareName']))
  1539. del(connData['ConnectedShares'][recvPacket['Tid']])
  1540. errorCode = STATUS_SUCCESS
  1541. else:
  1542. # STATUS_SMB_BAD_TID
  1543. errorCode = STATUS_SMB_BAD_TID
  1544. respSMBCommand['Parameters'] = respParameters
  1545. respSMBCommand['Data'] = respData
  1546. smbServer.setConnectionData(connId, connData)
  1547. return [respSMBCommand], None, errorCode
  1548. @staticmethod
  1549. def smbComLogOffAndX(connId, smbServer, SMBCommand, recvPacket):
  1550. connData = smbServer.getConnectionData(connId)
  1551. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_LOGOFF_ANDX)
  1552. # Check if the Uid matches the user trying to logoff
  1553. respParameters = ''
  1554. respData = ''
  1555. if recvPacket['Uid'] != connData['Uid']:
  1556. # STATUS_SMB_BAD_UID
  1557. errorCode = STATUS_SMB_BAD_UID
  1558. else:
  1559. errorCode = STATUS_SUCCESS
  1560. respSMBCommand['Parameters'] = respParameters
  1561. respSMBCommand['Data'] = respData
  1562. connData['Uid'] = 0
  1563. smbServer.setConnectionData(connId, connData)
  1564. return [respSMBCommand], None, errorCode
  1565. @staticmethod
  1566. def smbComQueryInformation2(connId, smbServer, SMBCommand, recvPacket):
  1567. connData = smbServer.getConnectionData(connId)
  1568. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_QUERY_INFORMATION2)
  1569. respParameters = smb.SMBQueryInformation2Response_Parameters()
  1570. respData = ''
  1571. queryInformation2 = smb.SMBQueryInformation2_Parameters(SMBCommand['Parameters'])
  1572. errorCode = 0xFF
  1573. if connData['OpenedFiles'].has_key(queryInformation2['Fid']):
  1574. errorCode = STATUS_SUCCESS
  1575. pathName = connData['OpenedFiles'][queryInformation2['Fid']]['FileName']
  1576. try:
  1577. (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(pathName)
  1578. respParameters['CreateDate'] = getSMBDate(ctime)
  1579. respParameters['CreationTime'] = getSMBTime(ctime)
  1580. respParameters['LastAccessDate'] = getSMBDate(atime)
  1581. respParameters['LastAccessTime'] = getSMBTime(atime)
  1582. respParameters['LastWriteDate'] = getSMBDate(mtime)
  1583. respParameters['LastWriteTime'] = getSMBTime(mtime)
  1584. respParameters['FileDataSize'] = size
  1585. respParameters['FileAllocationSize'] = size
  1586. attribs = 0
  1587. if os.path.isdir(pathName):
  1588. attribs = smb.SMB_FILE_ATTRIBUTE_DIRECTORY
  1589. if os.path.isfile(pathName):
  1590. attribs = smb.SMB_FILE_ATTRIBUTE_NORMAL
  1591. respParameters['FileAttributes'] = attribs
  1592. except Exception, e:
  1593. smbServer.log('smbComQueryInformation2 %s' % e,logging.ERROR)
  1594. errorCode = STATUS_ACCESS_DENIED
  1595. if errorCode > 0:
  1596. respParameters = ''
  1597. respData = ''
  1598. respSMBCommand['Parameters'] = respParameters
  1599. respSMBCommand['Data'] = respData
  1600. smbServer.setConnectionData(connId, connData)
  1601. return [respSMBCommand], None, errorCode
  1602. @staticmethod
  1603. def smbComNtCreateAndX(connId, smbServer, SMBCommand, recvPacket):
  1604. # TODO: Fully implement this
  1605. connData = smbServer.getConnectionData(connId)
  1606. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_NT_CREATE_ANDX)
  1607. respParameters = smb.SMBNtCreateAndXResponse_Parameters()
  1608. respData = ''
  1609. ntCreateAndXParameters = smb.SMBNtCreateAndX_Parameters(SMBCommand['Parameters'])
  1610. ntCreateAndXData = smb.SMBNtCreateAndX_Data( flags = recvPacket['Flags2'], data = SMBCommand['Data'])
  1611. #if ntCreateAndXParameters['CreateFlags'] & 0x10: # NT_CREATE_REQUEST_EXTENDED_RESPONSE
  1612. # respParameters = smb.SMBNtCreateAndXExtendedResponse_Parameters()
  1613. # respParameters['VolumeGUID'] = '\x00'
  1614. # Get the Tid associated
  1615. if connData['ConnectedShares'].has_key(recvPacket['Tid']):
  1616. # If we have a rootFid, the path is relative to that fid
  1617. errorCode = STATUS_SUCCESS
  1618. if ntCreateAndXParameters['RootFid'] > 0:
  1619. path = connData['OpenedFiles'][ntCreateAndXParameters['RootFid']]['FileName']
  1620. LOG.debug("RootFid present %s!" % path)
  1621. else:
  1622. if connData['ConnectedShares'][recvPacket['Tid']].has_key('path'):
  1623. path = connData['ConnectedShares'][recvPacket['Tid']]['path']
  1624. else:
  1625. path = 'NONE'
  1626. errorCode = STATUS_ACCESS_DENIED
  1627. deleteOnClose = False
  1628. fileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],ntCreateAndXData['FileName']).replace('\\','/'))
  1629. if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
  1630. # strip leading '/'
  1631. fileName = fileName[1:]
  1632. pathName = os.path.join(path,fileName)
  1633. createDisposition = ntCreateAndXParameters['Disposition']
  1634. mode = 0
  1635. if createDisposition == smb.FILE_SUPERSEDE:
  1636. mode |= os.O_TRUNC | os.O_CREAT
  1637. elif createDisposition & smb.FILE_OVERWRITE_IF == smb.FILE_OVERWRITE_IF:
  1638. mode |= os.O_TRUNC | os.O_CREAT
  1639. elif createDisposition & smb.FILE_OVERWRITE == smb.FILE_OVERWRITE:
  1640. if os.path.exists(pathName) is True:
  1641. mode |= os.O_TRUNC
  1642. else:
  1643. errorCode = STATUS_NO_SUCH_FILE
  1644. elif createDisposition & smb.FILE_OPEN_IF == smb.FILE_OPEN_IF:
  1645. if os.path.exists(pathName) is True:
  1646. mode |= os.O_TRUNC
  1647. else:
  1648. mode |= os.O_TRUNC | os.O_CREAT
  1649. elif createDisposition & smb.FILE_CREATE == smb.FILE_CREATE:
  1650. if os.path.exists(pathName) is True:
  1651. errorCode = STATUS_OBJECT_NAME_COLLISION
  1652. else:
  1653. mode |= os.O_CREAT
  1654. elif createDisposition & smb.FILE_OPEN == smb.FILE_OPEN:
  1655. if os.path.exists(pathName) is not True and smbServer.getRegisteredNamedPipes().has_key(unicode(pathName)) is not True:
  1656. errorCode = STATUS_NO_SUCH_FILE
  1657. if errorCode == STATUS_SUCCESS:
  1658. desiredAccess = ntCreateAndXParameters['AccessMask']
  1659. if (desiredAccess & smb.FILE_READ_DATA) or (desiredAccess & smb.GENERIC_READ):
  1660. mode |= os.O_RDONLY
  1661. if (desiredAccess & smb.FILE_WRITE_DATA) or (desiredAccess & smb.GENERIC_WRITE):
  1662. if (desiredAccess & smb.FILE_READ_DATA) or (desiredAccess & smb.GENERIC_READ):
  1663. mode |= os.O_RDWR #| os.O_APPEND
  1664. else:
  1665. mode |= os.O_WRONLY #| os.O_APPEND
  1666. if desiredAccess & smb.GENERIC_ALL:
  1667. mode |= os.O_RDWR #| os.O_APPEND
  1668. createOptions = ntCreateAndXParameters['CreateOptions']
  1669. if mode & os.O_CREAT == os.O_CREAT:
  1670. if createOptions & smb.FILE_DIRECTORY_FILE == smb.FILE_DIRECTORY_FILE:
  1671. try:
  1672. # Let's create the directory
  1673. os.mkdir(pathName)
  1674. mode = os.O_RDONLY
  1675. except Exception, e:
  1676. smbServer.log("NTCreateAndX: %s,%s,%s" % (pathName,mode,e),logging.ERROR)
  1677. errorCode = STATUS_ACCESS_DENIED
  1678. if createOptions & smb.FILE_NON_DIRECTORY_FILE == smb.FILE_NON_DIRECTORY_FILE:
  1679. # If the file being opened is a directory, the server MUST fail the request with
  1680. # STATUS_FILE_IS_A_DIRECTORY in the Status field of the SMB Header in the server
  1681. # response.
  1682. if os.path.isdir(pathName) is True:
  1683. errorCode = STATUS_FILE_IS_A_DIRECTORY
  1684. if createOptions & smb.FILE_DELETE_ON_CLOSE == smb.FILE_DELETE_ON_CLOSE:
  1685. deleteOnClose = True
  1686. if errorCode == STATUS_SUCCESS:
  1687. try:
  1688. if os.path.isdir(pathName) and sys.platform == 'win32':
  1689. fid = VOID_FILE_DESCRIPTOR
  1690. else:
  1691. if sys.platform == 'win32':
  1692. mode |= os.O_BINARY
  1693. if smbServer.getRegisteredNamedPipes().has_key(unicode(pathName)):
  1694. fid = PIPE_FILE_DESCRIPTOR
  1695. sock = socket.socket()
  1696. sock.connect(smbServer.getRegisteredNamedPipes()[unicode(pathName)])
  1697. else:
  1698. fid = os.open(pathName, mode)
  1699. except Exception, e:
  1700. smbServer.log("NTCreateAndX: %s,%s,%s" % (pathName,mode,e),logging.ERROR)
  1701. #print e
  1702. fid = 0
  1703. errorCode = STATUS_ACCESS_DENIED
  1704. else:
  1705. errorCode = STATUS_SMB_BAD_TID
  1706. if errorCode == STATUS_SUCCESS:
  1707. # Simple way to generate a fid
  1708. if len(connData['OpenedFiles']) == 0:
  1709. fakefid = 1
  1710. else:
  1711. fakefid = connData['OpenedFiles'].keys()[-1] + 1
  1712. respParameters['Fid'] = fakefid
  1713. respParameters['CreateAction'] = createDisposition
  1714. if fid == PIPE_FILE_DESCRIPTOR:
  1715. respParameters['FileAttributes'] = 0x80
  1716. respParameters['IsDirectory'] = 0
  1717. respParameters['CreateTime'] = 0
  1718. respParameters['LastAccessTime'] = 0
  1719. respParameters['LastWriteTime'] = 0
  1720. respParameters['LastChangeTime'] = 0
  1721. respParameters['AllocationSize'] = 4096
  1722. respParameters['EndOfFile'] = 0
  1723. respParameters['FileType'] = 2
  1724. respParameters['IPCState'] = 0x5ff
  1725. else:
  1726. if os.path.isdir(pathName):
  1727. respParameters['FileAttributes'] = smb.SMB_FILE_ATTRIBUTE_DIRECTORY
  1728. respParameters['IsDirectory'] = 1
  1729. else:
  1730. respParameters['IsDirectory'] = 0
  1731. respParameters['FileAttributes'] = ntCreateAndXParameters['FileAttributes']
  1732. # Let's get this file's information
  1733. respInfo, errorCode = queryPathInformation('',pathName,level= smb.SMB_QUERY_FILE_ALL_INFO)
  1734. if errorCode == STATUS_SUCCESS:
  1735. respParameters['CreateTime'] = respInfo['CreationTime']
  1736. respParameters['LastAccessTime'] = respInfo['LastAccessTime']
  1737. respParameters['LastWriteTime'] = respInfo['LastWriteTime']
  1738. respParameters['LastChangeTime'] = respInfo['LastChangeTime']
  1739. respParameters['FileAttributes'] = respInfo['ExtFileAttributes']
  1740. respParameters['AllocationSize'] = respInfo['AllocationSize']
  1741. respParameters['EndOfFile'] = respInfo['EndOfFile']
  1742. else:
  1743. respParameters = ''
  1744. respData = ''
  1745. if errorCode == STATUS_SUCCESS:
  1746. # Let's store the fid for the connection
  1747. # smbServer.log('Create file %s, mode:0x%x' % (pathName, mode))
  1748. connData['OpenedFiles'][fakefid] = {}
  1749. connData['OpenedFiles'][fakefid]['FileHandle'] = fid
  1750. connData['OpenedFiles'][fakefid]['FileName'] = pathName
  1751. connData['OpenedFiles'][fakefid]['DeleteOnClose'] = deleteOnClose
  1752. if fid == PIPE_FILE_DESCRIPTOR:
  1753. connData['OpenedFiles'][fakefid]['Socket'] = sock
  1754. else:
  1755. respParameters = ''
  1756. respData = ''
  1757. respSMBCommand['Parameters'] = respParameters
  1758. respSMBCommand['Data'] = respData
  1759. smbServer.setConnectionData(connId, connData)
  1760. return [respSMBCommand], None, errorCode
  1761. @staticmethod
  1762. def smbComOpenAndX(connId, smbServer, SMBCommand, recvPacket):
  1763. connData = smbServer.getConnectionData(connId)
  1764. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_OPEN_ANDX)
  1765. respParameters = smb.SMBOpenAndXResponse_Parameters()
  1766. respData = ''
  1767. openAndXParameters = smb.SMBOpenAndX_Parameters(SMBCommand['Parameters'])
  1768. openAndXData = smb.SMBOpenAndX_Data( flags = recvPacket['Flags2'], data = SMBCommand['Data'])
  1769. # Get the Tid associated
  1770. if connData['ConnectedShares'].has_key(recvPacket['Tid']):
  1771. path = connData['ConnectedShares'][recvPacket['Tid']]['path']
  1772. openedFile, mode, pathName, errorCode = openFile(path,
  1773. decodeSMBString(recvPacket['Flags2'],openAndXData['FileName']),
  1774. openAndXParameters['DesiredAccess'],
  1775. openAndXParameters['FileAttributes'],
  1776. openAndXParameters['OpenMode'])
  1777. else:
  1778. errorCode = STATUS_SMB_BAD_TID
  1779. if errorCode == STATUS_SUCCESS:
  1780. # Simple way to generate a fid
  1781. fid = len(connData['OpenedFiles']) + 1
  1782. if len(connData['OpenedFiles']) == 0:
  1783. fid = 1
  1784. else:
  1785. fid = connData['OpenedFiles'].keys()[-1] + 1
  1786. respParameters['Fid'] = fid
  1787. if mode & os.O_CREAT:
  1788. # File did not exist and was created
  1789. respParameters['Action'] = 0x2
  1790. elif mode & os.O_RDONLY:
  1791. # File existed and was opened
  1792. respParameters['Action'] = 0x1
  1793. elif mode & os.O_APPEND:
  1794. # File existed and was opened
  1795. respParameters['Action'] = 0x1
  1796. else:
  1797. # File existed and was truncated
  1798. respParameters['Action'] = 0x3
  1799. # Let's store the fid for the connection
  1800. #smbServer.log('Opening file %s' % pathName)
  1801. connData['OpenedFiles'][fid] = {}
  1802. connData['OpenedFiles'][fid]['FileHandle'] = openedFile
  1803. connData['OpenedFiles'][fid]['FileName'] = pathName
  1804. connData['OpenedFiles'][fid]['DeleteOnClose'] = False
  1805. else:
  1806. respParameters = ''
  1807. respData = ''
  1808. respSMBCommand['Parameters'] = respParameters
  1809. respSMBCommand['Data'] = respData
  1810. smbServer.setConnectionData(connId, connData)
  1811. return [respSMBCommand], None, errorCode
  1812. @staticmethod
  1813. def smbComTreeConnectAndX(connId, smbServer, SMBCommand, recvPacket):
  1814. connData = smbServer.getConnectionData(connId)
  1815. resp = smb.NewSMBPacket()
  1816. resp['Flags1'] = smb.SMB.FLAGS1_REPLY
  1817. resp['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_LONG_NAMES | recvPacket['Flags2'] & smb.SMB.FLAGS2_UNICODE
  1818. resp['Tid'] = recvPacket['Tid']
  1819. resp['Mid'] = recvPacket['Mid']
  1820. resp['Pid'] = connData['Pid']
  1821. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_TREE_CONNECT_ANDX)
  1822. respParameters = smb.SMBTreeConnectAndXResponse_Parameters()
  1823. respData = smb.SMBTreeConnectAndXResponse_Data()
  1824. treeConnectAndXParameters = smb.SMBTreeConnectAndX_Parameters(SMBCommand['Parameters'])
  1825. if treeConnectAndXParameters['Flags'] & 0x8:
  1826. respParameters = smb.SMBTreeConnectAndXExtendedResponse_Parameters()
  1827. treeConnectAndXData = smb.SMBTreeConnectAndX_Data( flags = recvPacket['Flags2'] )
  1828. treeConnectAndXData['_PasswordLength'] = treeConnectAndXParameters['PasswordLength']
  1829. treeConnectAndXData.fromString(SMBCommand['Data'])
  1830. errorCode = STATUS_SUCCESS
  1831. ## Process here the request, does the share exist?
  1832. UNCOrShare = decodeSMBString(recvPacket['Flags2'], treeConnectAndXData['Path'])
  1833. # Is this a UNC?
  1834. if ntpath.ismount(UNCOrShare):
  1835. path = UNCOrShare.split('\\')[3]
  1836. else:
  1837. path = ntpath.basename(UNCOrShare)
  1838. share = searchShare(connId, path, smbServer)
  1839. if share is not None:
  1840. # Simple way to generate a Tid
  1841. if len(connData['ConnectedShares']) == 0:
  1842. tid = 1
  1843. else:
  1844. tid = connData['ConnectedShares'].keys()[-1] + 1
  1845. connData['ConnectedShares'][tid] = share
  1846. connData['ConnectedShares'][tid]['shareName'] = path
  1847. resp['Tid'] = tid
  1848. #smbServer.log("Connecting Share(%d:%s)" % (tid,path))
  1849. else:
  1850. smbServer.log("TreeConnectAndX not found %s" % path, logging.ERROR)
  1851. errorCode = STATUS_OBJECT_PATH_NOT_FOUND
  1852. resp['ErrorCode'] = errorCode >> 16
  1853. resp['ErrorClass'] = errorCode & 0xff
  1854. ##
  1855. respParameters['OptionalSupport'] = smb.SMB.SMB_SUPPORT_SEARCH_BITS
  1856. if path == 'IPC$':
  1857. respData['Service'] = 'IPC'
  1858. else:
  1859. respData['Service'] = path
  1860. respData['PadLen'] = 0
  1861. respData['NativeFileSystem'] = encodeSMBString(recvPacket['Flags2'], 'NTFS' )
  1862. respSMBCommand['Parameters'] = respParameters
  1863. respSMBCommand['Data'] = respData
  1864. resp['Uid'] = connData['Uid']
  1865. resp.addCommand(respSMBCommand)
  1866. smbServer.setConnectionData(connId, connData)
  1867. return None, [resp], errorCode
  1868. @staticmethod
  1869. def smbComSessionSetupAndX(connId, smbServer, SMBCommand, recvPacket):
  1870. connData = smbServer.getConnectionData(connId, checkStatus = False)
  1871. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_SESSION_SETUP_ANDX)
  1872. # From [MS-SMB]
  1873. # When extended security is being used (see section 3.2.4.2.4), the
  1874. # request MUST take the following form
  1875. # [..]
  1876. # WordCount (1 byte): The value of this field MUST be 0x0C.
  1877. if SMBCommand['WordCount'] == 12:
  1878. # Extended security. Here we deal with all SPNEGO stuff
  1879. respParameters = smb.SMBSessionSetupAndX_Extended_Response_Parameters()
  1880. respData = smb.SMBSessionSetupAndX_Extended_Response_Data(flags = recvPacket['Flags2'])
  1881. sessionSetupParameters = smb.SMBSessionSetupAndX_Extended_Parameters(SMBCommand['Parameters'])
  1882. sessionSetupData = smb.SMBSessionSetupAndX_Extended_Data()
  1883. sessionSetupData['SecurityBlobLength'] = sessionSetupParameters['SecurityBlobLength']
  1884. sessionSetupData.fromString(SMBCommand['Data'])
  1885. connData['Capabilities'] = sessionSetupParameters['Capabilities']
  1886. rawNTLM = False
  1887. if struct.unpack('B',sessionSetupData['SecurityBlob'][0])[0] == ASN1_AID:
  1888. # NEGOTIATE packet
  1889. blob = SPNEGO_NegTokenInit(sessionSetupData['SecurityBlob'])
  1890. token = blob['MechToken']
  1891. if len(blob['MechTypes'][0]) > 0:
  1892. # Is this GSSAPI NTLM or something else we don't support?
  1893. mechType = blob['MechTypes'][0]
  1894. if mechType != TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']:
  1895. # Nope, do we know it?
  1896. if MechTypes.has_key(mechType):
  1897. mechStr = MechTypes[mechType]
  1898. else:
  1899. mechStr = hexlify(mechType)
  1900. smbServer.log("Unsupported MechType '%s'" % mechStr, logging.CRITICAL)
  1901. # We don't know the token, we answer back again saying
  1902. # we just support NTLM.
  1903. # ToDo: Build this into a SPNEGO_NegTokenResp()
  1904. respToken = '\xa1\x15\x30\x13\xa0\x03\x0a\x01\x03\xa1\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a'
  1905. respParameters['SecurityBlobLength'] = len(respToken)
  1906. respData['SecurityBlobLength'] = respParameters['SecurityBlobLength']
  1907. respData['SecurityBlob'] = respToken
  1908. respData['NativeOS'] = encodeSMBString(recvPacket['Flags2'], smbServer.getServerOS())
  1909. respData['NativeLanMan'] = encodeSMBString(recvPacket['Flags2'], smbServer.getServerOS())
  1910. respSMBCommand['Parameters'] = respParameters
  1911. respSMBCommand['Data'] = respData
  1912. return [respSMBCommand], None, STATUS_MORE_PROCESSING_REQUIRED
  1913. elif struct.unpack('B',sessionSetupData['SecurityBlob'][0])[0] == ASN1_SUPPORTED_MECH:
  1914. # AUTH packet
  1915. blob = SPNEGO_NegTokenResp(sessionSetupData['SecurityBlob'])
  1916. token = blob['ResponseToken']
  1917. else:
  1918. # No GSSAPI stuff, raw NTLMSSP
  1919. rawNTLM = True
  1920. token = sessionSetupData['SecurityBlob']
  1921. # Here we only handle NTLMSSP, depending on what stage of the
  1922. # authentication we are, we act on it
  1923. messageType = struct.unpack('<L',token[len('NTLMSSP\x00'):len('NTLMSSP\x00')+4])[0]
  1924. if messageType == 0x01:
  1925. # NEGOTIATE_MESSAGE
  1926. negotiateMessage = ntlm.NTLMAuthNegotiate()
  1927. negotiateMessage.fromString(token)
  1928. # Let's store it in the connection data
  1929. connData['NEGOTIATE_MESSAGE'] = negotiateMessage
  1930. # Let's build the answer flags
  1931. # TODO: Parse all the flags. With this we're leaving some clients out
  1932. ansFlags = 0
  1933. if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_56:
  1934. ansFlags |= ntlm.NTLMSSP_NEGOTIATE_56
  1935. if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_128:
  1936. ansFlags |= ntlm.NTLMSSP_NEGOTIATE_128
  1937. if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_KEY_EXCH:
  1938. ansFlags |= ntlm.NTLMSSP_NEGOTIATE_KEY_EXCH
  1939. if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:
  1940. ansFlags |= ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
  1941. if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_UNICODE:
  1942. ansFlags |= ntlm.NTLMSSP_NEGOTIATE_UNICODE
  1943. if negotiateMessage['flags'] & ntlm.NTLM_NEGOTIATE_OEM:
  1944. ansFlags |= ntlm.NTLM_NEGOTIATE_OEM
  1945. ansFlags |= ntlm.NTLMSSP_NEGOTIATE_VERSION | ntlm.NTLMSSP_NEGOTIATE_TARGET_INFO | ntlm.NTLMSSP_TARGET_TYPE_SERVER | ntlm.NTLMSSP_NEGOTIATE_NTLM | ntlm.NTLMSSP_REQUEST_TARGET
  1946. # Generate the AV_PAIRS
  1947. av_pairs = ntlm.AV_PAIRS()
  1948. # TODO: Put the proper data from SMBSERVER config
  1949. av_pairs[ntlm.NTLMSSP_AV_HOSTNAME] = av_pairs[ntlm.NTLMSSP_AV_DNS_HOSTNAME] = smbServer.getServerName().encode('utf-16le')
  1950. av_pairs[ntlm.NTLMSSP_AV_DOMAINNAME] = av_pairs[ntlm.NTLMSSP_AV_DNS_DOMAINNAME] = smbServer.getServerDomain().encode('utf-16le')
  1951. av_pairs[ntlm.NTLMSSP_AV_TIME] = struct.pack('<q', (116444736000000000 + calendar.timegm(time.gmtime()) * 10000000) )
  1952. challengeMessage = ntlm.NTLMAuthChallenge()
  1953. challengeMessage['flags'] = ansFlags
  1954. challengeMessage['domain_len'] = len(smbServer.getServerDomain().encode('utf-16le'))
  1955. challengeMessage['domain_max_len'] = challengeMessage['domain_len']
  1956. challengeMessage['domain_offset'] = 40 + 16
  1957. challengeMessage['challenge'] = smbServer.getSMBChallenge()
  1958. challengeMessage['domain_name'] = smbServer.getServerDomain().encode('utf-16le')
  1959. challengeMessage['TargetInfoFields_len'] = len(av_pairs)
  1960. challengeMessage['TargetInfoFields_max_len'] = len(av_pairs)
  1961. challengeMessage['TargetInfoFields'] = av_pairs
  1962. challengeMessage['TargetInfoFields_offset'] = 40 + 16 + len(challengeMessage['domain_name'])
  1963. challengeMessage['Version'] = '\xff'*8
  1964. challengeMessage['VersionLen'] = 8
  1965. if rawNTLM is False:
  1966. respToken = SPNEGO_NegTokenResp()
  1967. # accept-incomplete. We want more data
  1968. respToken['NegResult'] = '\x01'
  1969. respToken['SupportedMech'] = TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']
  1970. respToken['ResponseToken'] = challengeMessage.getData()
  1971. else:
  1972. respToken = challengeMessage
  1973. # Setting the packet to STATUS_MORE_PROCESSING
  1974. errorCode = STATUS_MORE_PROCESSING_REQUIRED
  1975. # Let's set up an UID for this connection and store it
  1976. # in the connection's data
  1977. # Picking a fixed value
  1978. # TODO: Manage more UIDs for the same session
  1979. connData['Uid'] = 10
  1980. # Let's store it in the connection data
  1981. connData['CHALLENGE_MESSAGE'] = challengeMessage
  1982. elif messageType == 0x02:
  1983. # CHALLENGE_MESSAGE
  1984. raise Exception('Challenge Message raise, not implemented!')
  1985. elif messageType == 0x03:
  1986. # AUTHENTICATE_MESSAGE, here we deal with authentication
  1987. authenticateMessage = ntlm.NTLMAuthChallengeResponse()
  1988. authenticateMessage.fromString(token)
  1989. smbServer.log("AUTHENTICATE_MESSAGE (%s\\%s,%s)" % (authenticateMessage['domain_name'], authenticateMessage['user_name'], authenticateMessage['host_name']))
  1990. # TODO: Check the credentials! Now granting permissions
  1991. respToken = SPNEGO_NegTokenResp()
  1992. # accept-completed
  1993. respToken['NegResult'] = '\x00'
  1994. # Status SUCCESS
  1995. errorCode = STATUS_SUCCESS
  1996. smbServer.log('User %s\\%s authenticated successfully' % (authenticateMessage['user_name'], authenticateMessage['host_name']))
  1997. # Let's store it in the connection data
  1998. connData['AUTHENTICATE_MESSAGE'] = authenticateMessage
  1999. try:
  2000. jtr_dump_path = smbServer.getJTRdumpPath()
  2001. ntlm_hash_data = outputToJohnFormat( connData['CHALLENGE_MESSAGE']['challenge'], authenticateMessage['user_name'], authenticateMessage['domain_name'], authenticateMessage['lanman'], authenticateMessage['ntlm'] )
  2002. smbServer.log(ntlm_hash_data['hash_string'])
  2003. if jtr_dump_path is not '':
  2004. writeJohnOutputToFile(ntlm_hash_data['hash_string'], ntlm_hash_data['hash_version'], jtr_dump_path)
  2005. except:
  2006. smbServer.log("Could not write NTLM Hashes to the specified JTR_Dump_Path %s" % jtr_dump_path)
  2007. else:
  2008. raise Exception("Unknown NTLMSSP MessageType %d" % messageType)
  2009. respParameters['SecurityBlobLength'] = len(respToken)
  2010. respData['SecurityBlobLength'] = respParameters['SecurityBlobLength']
  2011. respData['SecurityBlob'] = respToken.getData()
  2012. else:
  2013. # Process Standard Security
  2014. respParameters = smb.SMBSessionSetupAndXResponse_Parameters()
  2015. respData = smb.SMBSessionSetupAndXResponse_Data()
  2016. sessionSetupParameters = smb.SMBSessionSetupAndX_Parameters(SMBCommand['Parameters'])
  2017. sessionSetupData = smb.SMBSessionSetupAndX_Data()
  2018. sessionSetupData['AnsiPwdLength'] = sessionSetupParameters['AnsiPwdLength']
  2019. sessionSetupData['UnicodePwdLength'] = sessionSetupParameters['UnicodePwdLength']
  2020. sessionSetupData.fromString(SMBCommand['Data'])
  2021. connData['Capabilities'] = sessionSetupParameters['Capabilities']
  2022. # Do the verification here, for just now we grant access
  2023. # TODO: Manage more UIDs for the same session
  2024. errorCode = STATUS_SUCCESS
  2025. connData['Uid'] = 10
  2026. respParameters['Action'] = 0
  2027. smbServer.log('User %s\\%s authenticated successfully (basic)' % (sessionSetupData['PrimaryDomain'], sessionSetupData['Account']))
  2028. try:
  2029. jtr_dump_path = smbServer.getJTRdumpPath()
  2030. ntlm_hash_data = outputToJohnFormat( '', sessionSetupData['Account'], sessionSetupData['PrimaryDomain'], sessionSetupData['AnsiPwd'], sessionSetupData['UnicodePwd'] )
  2031. smbServer.log(ntlm_hash_data['hash_string'])
  2032. if jtr_dump_path is not '':
  2033. writeJohnOutputToFile(ntlm_hash_data['hash_string'], ntlm_hash_data['hash_version'], jtr_dump_path)
  2034. except:
  2035. smbServer.log("Could not write NTLM Hashes to the specified JTR_Dump_Path %s" % jtr_dump_path)
  2036. respData['NativeOS'] = encodeSMBString(recvPacket['Flags2'], smbServer.getServerOS())
  2037. respData['NativeLanMan'] = encodeSMBString(recvPacket['Flags2'], smbServer.getServerOS())
  2038. respSMBCommand['Parameters'] = respParameters
  2039. respSMBCommand['Data'] = respData
  2040. # From now on, the client can ask for other commands
  2041. connData['Authenticated'] = True
  2042. # For now, just switching to nobody
  2043. #os.setregid(65534,65534)
  2044. #os.setreuid(65534,65534)
  2045. smbServer.setConnectionData(connId, connData)
  2046. return [respSMBCommand], None, errorCode
  2047. @staticmethod
  2048. def smbComNegotiate(connId, smbServer, SMBCommand, recvPacket ):
  2049. connData = smbServer.getConnectionData(connId, checkStatus = False)
  2050. connData['Pid'] = recvPacket['Pid']
  2051. SMBCommand = smb.SMBCommand(recvPacket['Data'][0])
  2052. respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_NEGOTIATE)
  2053. resp = smb.NewSMBPacket()
  2054. resp['Flags1'] = smb.SMB.FLAGS1_REPLY
  2055. resp['Pid'] = connData['Pid']
  2056. resp['Tid'] = recvPacket['Tid']
  2057. resp['Mid'] = recvPacket['Mid']
  2058. # TODO: We support more dialects, and parse them accordingly
  2059. dialects = SMBCommand['Data'].split('\x02')
  2060. try:
  2061. index = dialects.index('NT LM 0.12\x00') - 1
  2062. # Let's fill the data for NTLM
  2063. if recvPacket['Flags2'] & smb.SMB.FLAGS2_EXTENDED_SECURITY:
  2064. resp['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_UNICODE
  2065. #resp['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS
  2066. _dialects_data = smb.SMBExtended_Security_Data()
  2067. _dialects_data['ServerGUID'] = 'A'*16
  2068. blob = SPNEGO_NegTokenInit()
  2069. blob['MechTypes'] = [TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']]
  2070. _dialects_data['SecurityBlob'] = blob.getData()
  2071. _dialects_parameters = smb.SMBExtended_Security_Parameters()
  2072. _dialects_parameters['Capabilities'] = smb.SMB.CAP_EXTENDED_SECURITY | smb.SMB.CAP_USE_NT_ERRORS | smb.SMB.CAP_NT_SMBS | smb.SMB.CAP_UNICODE
  2073. _dialects_parameters['ChallengeLength'] = 0
  2074. else:
  2075. resp['Flags2'] = smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_UNICODE
  2076. _dialects_parameters = smb.SMBNTLMDialect_Parameters()
  2077. _dialects_data= smb.SMBNTLMDialect_Data()
  2078. _dialects_data['Payload'] = ''
  2079. if connData.has_key('EncryptionKey'):
  2080. _dialects_data['Challenge'] = connData['EncryptionKey']
  2081. _dialects_parameters['ChallengeLength'] = len(str(_dialects_data))
  2082. else:
  2083. # TODO: Handle random challenges, now one that can be used with rainbow tables
  2084. _dialects_data['Challenge'] = '\x11\x22\x33\x44\x55\x66\x77\x88'
  2085. _dialects_parameters['ChallengeLength'] = 8
  2086. _dialects_parameters['Capabilities'] = smb.SMB.CAP_USE_NT_ERRORS | smb.SMB.CAP_NT_SMBS
  2087. # Let's see if we need to support RPC_REMOTE_APIS
  2088. config = smbServer.getServerConfig()
  2089. if config.has_option('global','rpc_apis'):
  2090. if config.getboolean('global', 'rpc_apis') is True:
  2091. _dialects_parameters['Capabilities'] |= smb.SMB.CAP_RPC_REMOTE_APIS
  2092. _dialects_parameters['DialectIndex'] = index
  2093. _dialects_parameters['SecurityMode'] = smb.SMB.SECURITY_AUTH_ENCRYPTED | smb.SMB.SECURITY_SHARE_USER
  2094. _dialects_parameters['MaxMpxCount'] = 1
  2095. _dialects_parameters['MaxNumberVcs'] = 1
  2096. _dialects_parameters['MaxBufferSize'] = 64000
  2097. _dialects_parameters['MaxRawSize'] = 65536
  2098. _dialects_parameters['SessionKey'] = 0
  2099. _dialects_parameters['LowDateTime'] = 0
  2100. _dialects_parameters['HighDateTime'] = 0
  2101. _dialects_parameters['ServerTimeZone'] = 0
  2102. respSMBCommand['Data'] = _dialects_data
  2103. respSMBCommand['Parameters'] = _dialects_parameters
  2104. connData['_dialects_data'] = _dialects_data
  2105. connData['_dialects_parameters'] = _dialects_parameters
  2106. except Exception, e:
  2107. # No NTLM throw an error
  2108. smbServer.log('smbComNegotiate: %s' % e, logging.ERROR)
  2109. respSMBCommand['Data'] = struct.pack('<H',0xffff)
  2110. smbServer.setConnectionData(connId, connData)
  2111. resp.addCommand(respSMBCommand)
  2112. return None, [resp], STATUS_SUCCESS
  2113. @staticmethod
  2114. def default(connId, smbServer, SMBCommand, recvPacket):
  2115. # By default we return an SMB Packet with error not implemented
  2116. smbServer.log("Not implemented command: 0x%x" % recvPacket['Command'],logging.DEBUG)
  2117. packet = smb.NewSMBPacket()
  2118. packet['Flags1'] = smb.SMB.FLAGS1_REPLY
  2119. packet['Flags2'] = smb.SMB.FLAGS2_NT_STATUS
  2120. packet['Command'] = recvPacket['Command']
  2121. packet['Pid'] = recvPacket['Pid']
  2122. packet['Tid'] = recvPacket['Tid']
  2123. packet['Mid'] = recvPacket['Mid']
  2124. packet['Uid'] = recvPacket['Uid']
  2125. packet['Data'] = '\x00\x00\x00'
  2126. errorCode = STATUS_NOT_IMPLEMENTED
  2127. packet['ErrorCode'] = errorCode >> 16
  2128. packet['ErrorClass'] = errorCode & 0xff
  2129. return None, [packet], errorCode
  2130. class SMB2Commands:
  2131. @staticmethod
  2132. def smb2Negotiate(connId, smbServer, recvPacket, isSMB1 = False):
  2133. connData = smbServer.getConnectionData(connId, checkStatus = False)
  2134. respPacket = smb2.SMB2Packet()
  2135. respPacket['Flags'] = smb2.SMB2_FLAGS_SERVER_TO_REDIR
  2136. respPacket['Status'] = STATUS_SUCCESS
  2137. respPacket['CreditRequestResponse'] = 1
  2138. respPacket['Command'] = smb2.SMB2_NEGOTIATE
  2139. respPacket['SessionID'] = 0
  2140. if isSMB1 is False:
  2141. respPacket['MessageID'] = recvPacket['MessageID']
  2142. else:
  2143. respPacket['MessageID'] = 0
  2144. respPacket['TreeID'] = 0
  2145. respSMBCommand = smb2.SMB2Negotiate_Response()
  2146. respSMBCommand['SecurityMode'] = 1
  2147. if isSMB1 is True:
  2148. # Let's first parse the packet to see if the client supports SMB2
  2149. SMBCommand = smb.SMBCommand(recvPacket['Data'][0])
  2150. dialects = SMBCommand['Data'].split('\x02')
  2151. if 'SMB 2.002\x00' in dialects or 'SMB 2.???\x00' in dialects:
  2152. respSMBCommand['DialectRevision'] = smb2.SMB2_DIALECT_002
  2153. else:
  2154. # Client does not support SMB2 fallbacking
  2155. raise Exception('SMB2 not supported, fallbacking')
  2156. else:
  2157. respSMBCommand['DialectRevision'] = smb2.SMB2_DIALECT_002
  2158. respSMBCommand['ServerGuid'] = 'A'*16
  2159. respSMBCommand['Capabilities'] = 0
  2160. respSMBCommand['MaxTransactSize'] = 65536
  2161. respSMBCommand['MaxReadSize'] = 65536
  2162. respSMBCommand['MaxWriteSize'] = 65536
  2163. respSMBCommand['SystemTime'] = getFileTime(calendar.timegm(time.gmtime()))
  2164. respSMBCommand['ServerStartTime'] = getFileTime(calendar.timegm(time.gmtime()))
  2165. respSMBCommand['SecurityBufferOffset'] = 0x80
  2166. blob = SPNEGO_NegTokenInit()
  2167. blob['MechTypes'] = [TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']]
  2168. respSMBCommand['Buffer'] = blob.getData()
  2169. respSMBCommand['SecurityBufferLength'] = len(respSMBCommand['Buffer'])
  2170. respPacket['Data'] = respSMBCommand
  2171. smbServer.setConnectionData(connId, connData)
  2172. return None, [respPacket], STATUS_SUCCESS
  2173. @staticmethod
  2174. def smb2SessionSetup(connId, smbServer, recvPacket):
  2175. connData = smbServer.getConnectionData(connId, checkStatus = False)
  2176. respSMBCommand = smb2.SMB2SessionSetup_Response()
  2177. sessionSetupData = smb2.SMB2SessionSetup(recvPacket['Data'])
  2178. connData['Capabilities'] = sessionSetupData['Capabilities']
  2179. securityBlob = sessionSetupData['Buffer']
  2180. rawNTLM = False
  2181. if struct.unpack('B',securityBlob[0])[0] == ASN1_AID:
  2182. # NEGOTIATE packet
  2183. blob = SPNEGO_NegTokenInit(securityBlob)
  2184. token = blob['MechToken']
  2185. if len(blob['MechTypes'][0]) > 0:
  2186. # Is this GSSAPI NTLM or something else we don't support?
  2187. mechType = blob['MechTypes'][0]
  2188. if mechType != TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']:
  2189. # Nope, do we know it?
  2190. if MechTypes.has_key(mechType):
  2191. mechStr = MechTypes[mechType]
  2192. else:
  2193. mechStr = hexlify(mechType)
  2194. smbServer.log("Unsupported MechType '%s'" % mechStr, logging.CRITICAL)
  2195. # We don't know the token, we answer back again saying
  2196. # we just support NTLM.
  2197. # ToDo: Build this into a SPNEGO_NegTokenResp()
  2198. respToken = '\xa1\x15\x30\x13\xa0\x03\x0a\x01\x03\xa1\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a'
  2199. respSMBCommand['SecurityBufferOffset'] = 0x48
  2200. respSMBCommand['SecurityBufferLength'] = len(respToken)
  2201. respSMBCommand['Buffer'] = respToken
  2202. return [respSMBCommand], None, STATUS_MORE_PROCESSING_REQUIRED
  2203. elif struct.unpack('B',securityBlob[0])[0] == ASN1_SUPPORTED_MECH:
  2204. # AUTH packet
  2205. blob = SPNEGO_NegTokenResp(securityBlob)
  2206. token = blob['ResponseToken']
  2207. else:
  2208. # No GSSAPI stuff, raw NTLMSSP
  2209. rawNTLM = True
  2210. token = securityBlob
  2211. # Here we only handle NTLMSSP, depending on what stage of the
  2212. # authentication we are, we act on it
  2213. messageType = struct.unpack('<L',token[len('NTLMSSP\x00'):len('NTLMSSP\x00')+4])[0]
  2214. if messageType == 0x01:
  2215. # NEGOTIATE_MESSAGE
  2216. negotiateMessage = ntlm.NTLMAuthNegotiate()
  2217. negotiateMessage.fromString(token)
  2218. # Let's store it in the connection data
  2219. connData['NEGOTIATE_MESSAGE'] = negotiateMessage
  2220. # Let's build the answer flags
  2221. # TODO: Parse all the flags. With this we're leaving some clients out
  2222. ansFlags = 0
  2223. if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_56:
  2224. ansFlags |= ntlm.NTLMSSP_NEGOTIATE_56
  2225. if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_128:
  2226. ansFlags |= ntlm.NTLMSSP_NEGOTIATE_128
  2227. if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_KEY_EXCH:
  2228. ansFlags |= ntlm.NTLMSSP_NEGOTIATE_KEY_EXCH
  2229. if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:
  2230. ansFlags |= ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
  2231. if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_UNICODE:
  2232. ansFlags |= ntlm.NTLMSSP_NEGOTIATE_UNICODE
  2233. if negotiateMessage['flags'] & ntlm.NTLM_NEGOTIATE_OEM:
  2234. ansFlags |= ntlm.NTLM_NEGOTIATE_OEM
  2235. ansFlags |= ntlm.NTLMSSP_NEGOTIATE_VERSION | ntlm.NTLMSSP_NEGOTIATE_TARGET_INFO | ntlm.NTLMSSP_TARGET_TYPE_SERVER | ntlm.NTLMSSP_NEGOTIATE_NTLM | ntlm.NTLMSSP_REQUEST_TARGET
  2236. # Generate the AV_PAIRS
  2237. av_pairs = ntlm.AV_PAIRS()
  2238. # TODO: Put the proper data from SMBSERVER config
  2239. av_pairs[ntlm.NTLMSSP_AV_HOSTNAME] = av_pairs[ntlm.NTLMSSP_AV_DNS_HOSTNAME] = smbServer.getServerName().encode('utf-16le')
  2240. av_pairs[ntlm.NTLMSSP_AV_DOMAINNAME] = av_pairs[ntlm.NTLMSSP_AV_DNS_DOMAINNAME] = smbServer.getServerDomain().encode('utf-16le')
  2241. av_pairs[ntlm.NTLMSSP_AV_TIME] = struct.pack('<q', (116444736000000000 + calendar.timegm(time.gmtime()) * 10000000) )
  2242. challengeMessage = ntlm.NTLMAuthChallenge()
  2243. challengeMessage['flags'] = ansFlags
  2244. challengeMessage['domain_len'] = len(smbServer.getServerDomain().encode('utf-16le'))
  2245. challengeMessage['domain_max_len'] = challengeMessage['domain_len']
  2246. challengeMessage['domain_offset'] = 40 + 16
  2247. challengeMessage['challenge'] = smbServer.getSMBChallenge()
  2248. challengeMessage['domain_name'] = smbServer.getServerDomain().encode('utf-16le')
  2249. challengeMessage['TargetInfoFields_len'] = len(av_pairs)
  2250. challengeMessage['TargetInfoFields_max_len'] = len(av_pairs)
  2251. challengeMessage['TargetInfoFields'] = av_pairs
  2252. challengeMessage['TargetInfoFields_offset'] = 40 + 16 + len(challengeMessage['domain_name'])
  2253. challengeMessage['Version'] = '\xff'*8
  2254. challengeMessage['VersionLen'] = 8
  2255. if rawNTLM is False:
  2256. respToken = SPNEGO_NegTokenResp()
  2257. # accept-incomplete. We want more data
  2258. respToken['NegResult'] = '\x01'
  2259. respToken['SupportedMech'] = TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']
  2260. respToken['ResponseToken'] = challengeMessage.getData()
  2261. else:
  2262. respToken = challengeMessage
  2263. # Setting the packet to STATUS_MORE_PROCESSING
  2264. errorCode = STATUS_MORE_PROCESSING_REQUIRED
  2265. # Let's set up an UID for this connection and store it
  2266. # in the connection's data
  2267. # Picking a fixed value
  2268. # TODO: Manage more UIDs for the same session
  2269. connData['Uid'] = random.randint(1,0xffffffff)
  2270. # Let's store it in the connection data
  2271. connData['CHALLENGE_MESSAGE'] = challengeMessage
  2272. elif messageType == 0x02:
  2273. # CHALLENGE_MESSAGE
  2274. raise Exception('Challenge Message raise, not implemented!')
  2275. elif messageType == 0x03:
  2276. # AUTHENTICATE_MESSAGE, here we deal with authentication
  2277. authenticateMessage = ntlm.NTLMAuthChallengeResponse()
  2278. authenticateMessage.fromString(token)
  2279. smbServer.log("AUTHENTICATE_MESSAGE (%s\\%s,%s)" % (authenticateMessage['domain_name'], authenticateMessage['user_name'], authenticateMessage['host_name']))
  2280. # TODO: Check the credentials! Now granting permissions
  2281. respToken = SPNEGO_NegTokenResp()
  2282. # accept-completed
  2283. respToken['NegResult'] = '\x00'
  2284. # Status SUCCESS
  2285. errorCode = STATUS_SUCCESS
  2286. smbServer.log('User %s\\%s authenticated successfully' % (authenticateMessage['user_name'], authenticateMessage['host_name']))
  2287. # Let's store it in the connection data
  2288. connData['AUTHENTICATE_MESSAGE'] = authenticateMessage
  2289. try:
  2290. jtr_dump_path = smbServer.getJTRdumpPath()
  2291. ntlm_hash_data = outputToJohnFormat( connData['CHALLENGE_MESSAGE']['challenge'], authenticateMessage['user_name'], authenticateMessage['domain_name'], authenticateMessage['lanman'], authenticateMessage['ntlm'] )
  2292. smbServer.log(ntlm_hash_data['hash_string'])
  2293. if jtr_dump_path is not '':
  2294. writeJohnOutputToFile(ntlm_hash_data['hash_string'], ntlm_hash_data['hash_version'], jtr_dump_path)
  2295. except:
  2296. smbServer.log("Could not write NTLM Hashes to the specified JTR_Dump_Path %s" % jtr_dump_path)
  2297. respSMBCommand['SessionFlags'] = 1
  2298. else:
  2299. raise Exception("Unknown NTLMSSP MessageType %d" % messageType)
  2300. respSMBCommand['SecurityBufferOffset'] = 0x48
  2301. respSMBCommand['SecurityBufferLength'] = len(respToken)
  2302. respSMBCommand['Buffer'] = respToken.getData()
  2303. # From now on, the client can ask for other commands
  2304. connData['Authenticated'] = True
  2305. # For now, just switching to nobody
  2306. #os.setregid(65534,65534)
  2307. #os.setreuid(65534,65534)
  2308. smbServer.setConnectionData(connId, connData)
  2309. return [respSMBCommand], None, errorCode
  2310. @staticmethod
  2311. def smb2TreeConnect(connId, smbServer, recvPacket):
  2312. connData = smbServer.getConnectionData(connId)
  2313. respPacket = smb2.SMB2Packet()
  2314. respPacket['Flags'] = smb2.SMB2_FLAGS_SERVER_TO_REDIR
  2315. respPacket['Status'] = STATUS_SUCCESS
  2316. respPacket['CreditRequestResponse'] = 1
  2317. respPacket['Command'] = recvPacket['Command']
  2318. respPacket['SessionID'] = connData['Uid']
  2319. respPacket['Reserved'] = recvPacket['Reserved']
  2320. respPacket['MessageID'] = recvPacket['MessageID']
  2321. respPacket['TreeID'] = recvPacket['TreeID']
  2322. respSMBCommand = smb2.SMB2TreeConnect_Response()
  2323. treeConnectRequest = smb2.SMB2TreeConnect(recvPacket['Data'])
  2324. errorCode = STATUS_SUCCESS
  2325. ## Process here the request, does the share exist?
  2326. path = str(recvPacket)[treeConnectRequest['PathOffset']:][:treeConnectRequest['PathLength']]
  2327. UNCOrShare = path.decode('utf-16le')
  2328. # Is this a UNC?
  2329. if ntpath.ismount(UNCOrShare):
  2330. path = UNCOrShare.split('\\')[3]
  2331. else:
  2332. path = ntpath.basename(UNCOrShare)
  2333. share = searchShare(connId, path.upper(), smbServer)
  2334. if share is not None:
  2335. # Simple way to generate a Tid
  2336. if len(connData['ConnectedShares']) == 0:
  2337. tid = 1
  2338. else:
  2339. tid = connData['ConnectedShares'].keys()[-1] + 1
  2340. connData['ConnectedShares'][tid] = share
  2341. connData['ConnectedShares'][tid]['shareName'] = path
  2342. respPacket['TreeID'] = tid
  2343. smbServer.log("Connecting Share(%d:%s)" % (tid,path))
  2344. else:
  2345. smbServer.log("SMB2_TREE_CONNECT not found %s" % path, logging.ERROR)
  2346. errorCode = STATUS_OBJECT_PATH_NOT_FOUND
  2347. respPacket['Status'] = errorCode
  2348. ##
  2349. if path == 'IPC$':
  2350. respSMBCommand['ShareType'] = smb2.SMB2_SHARE_TYPE_PIPE
  2351. respSMBCommand['ShareFlags'] = 0x30
  2352. else:
  2353. respSMBCommand['ShareType'] = smb2.SMB2_SHARE_TYPE_DISK
  2354. respSMBCommand['ShareFlags'] = 0x0
  2355. respSMBCommand['Capabilities'] = 0
  2356. respSMBCommand['MaximalAccess'] = 0x000f01ff
  2357. respPacket['Data'] = respSMBCommand
  2358. smbServer.setConnectionData(connId, connData)
  2359. return None, [respPacket], errorCode
  2360. @staticmethod
  2361. def smb2Create(connId, smbServer, recvPacket):
  2362. connData = smbServer.getConnectionData(connId)
  2363. respSMBCommand = smb2.SMB2Create_Response()
  2364. ntCreateRequest = smb2.SMB2Create(recvPacket['Data'])
  2365. respSMBCommand['Buffer'] = '\x00'
  2366. # Get the Tid associated
  2367. if connData['ConnectedShares'].has_key(recvPacket['TreeID']):
  2368. # If we have a rootFid, the path is relative to that fid
  2369. errorCode = STATUS_SUCCESS
  2370. if connData['ConnectedShares'][recvPacket['TreeID']].has_key('path'):
  2371. path = connData['ConnectedShares'][recvPacket['TreeID']]['path']
  2372. else:
  2373. path = 'NONE'
  2374. errorCode = STATUS_ACCESS_DENIED
  2375. deleteOnClose = False
  2376. fileName = os.path.normpath(ntCreateRequest['Buffer'][:ntCreateRequest['NameLength']].decode('utf-16le').replace('\\','/'))
  2377. if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
  2378. # strip leading '/'
  2379. fileName = fileName[1:]
  2380. pathName = os.path.join(path,fileName)
  2381. createDisposition = ntCreateRequest['CreateDisposition']
  2382. mode = 0
  2383. if createDisposition == smb2.FILE_SUPERSEDE:
  2384. mode |= os.O_TRUNC | os.O_CREAT
  2385. elif createDisposition & smb2.FILE_OVERWRITE_IF == smb2.FILE_OVERWRITE_IF:
  2386. mode |= os.O_TRUNC | os.O_CREAT
  2387. elif createDisposition & smb2.FILE_OVERWRITE == smb2.FILE_OVERWRITE:
  2388. if os.path.exists(pathName) is True:
  2389. mode |= os.O_TRUNC
  2390. else:
  2391. errorCode = STATUS_NO_SUCH_FILE
  2392. elif createDisposition & smb2.FILE_OPEN_IF == smb2.FILE_OPEN_IF:
  2393. if os.path.exists(pathName) is True:
  2394. mode |= os.O_TRUNC
  2395. else:
  2396. mode |= os.O_TRUNC | os.O_CREAT
  2397. elif createDisposition & smb2.FILE_CREATE == smb2.FILE_CREATE:
  2398. if os.path.exists(pathName) is True:
  2399. errorCode = STATUS_OBJECT_NAME_COLLISION
  2400. else:
  2401. mode |= os.O_CREAT
  2402. elif createDisposition & smb2.FILE_OPEN == smb2.FILE_OPEN:
  2403. if os.path.exists(pathName) is not True and smbServer.getRegisteredNamedPipes().has_key(unicode(pathName)) is not True:
  2404. errorCode = STATUS_NO_SUCH_FILE
  2405. if errorCode == STATUS_SUCCESS:
  2406. desiredAccess = ntCreateRequest['DesiredAccess']
  2407. if (desiredAccess & smb2.FILE_READ_DATA) or (desiredAccess & smb2.GENERIC_READ):
  2408. mode |= os.O_RDONLY
  2409. if (desiredAccess & smb2.FILE_WRITE_DATA) or (desiredAccess & smb2.GENERIC_WRITE):
  2410. if (desiredAccess & smb2.FILE_READ_DATA) or (desiredAccess & smb2.GENERIC_READ):
  2411. mode |= os.O_RDWR #| os.O_APPEND
  2412. else:
  2413. mode |= os.O_WRONLY #| os.O_APPEND
  2414. if desiredAccess & smb2.GENERIC_ALL:
  2415. mode |= os.O_RDWR #| os.O_APPEND
  2416. createOptions = ntCreateRequest['CreateOptions']
  2417. if mode & os.O_CREAT == os.O_CREAT:
  2418. if createOptions & smb2.FILE_DIRECTORY_FILE == smb2.FILE_DIRECTORY_FILE:
  2419. try:
  2420. # Let's create the directory
  2421. os.mkdir(pathName)
  2422. mode = os.O_RDONLY
  2423. except Exception, e:
  2424. smbServer.log("SMB2_CREATE: %s,%s,%s" % (pathName,mode,e),logging.ERROR)
  2425. errorCode = STATUS_ACCESS_DENIED
  2426. if createOptions & smb2.FILE_NON_DIRECTORY_FILE == smb2.FILE_NON_DIRECTORY_FILE:
  2427. # If the file being opened is a directory, the server MUST fail the request with
  2428. # STATUS_FILE_IS_A_DIRECTORY in the Status field of the SMB Header in the server
  2429. # response.
  2430. if os.path.isdir(pathName) is True:
  2431. errorCode = STATUS_FILE_IS_A_DIRECTORY
  2432. if createOptions & smb2.FILE_DELETE_ON_CLOSE == smb2.FILE_DELETE_ON_CLOSE:
  2433. deleteOnClose = True
  2434. if errorCode == STATUS_SUCCESS:
  2435. try:
  2436. if os.path.isdir(pathName) and sys.platform == 'win32':
  2437. fid = VOID_FILE_DESCRIPTOR
  2438. else:
  2439. if sys.platform == 'win32':
  2440. mode |= os.O_BINARY
  2441. if smbServer.getRegisteredNamedPipes().has_key(unicode(pathName)):
  2442. fid = PIPE_FILE_DESCRIPTOR
  2443. sock = socket.socket()
  2444. sock.connect(smbServer.getRegisteredNamedPipes()[unicode(pathName)])
  2445. else:
  2446. fid = os.open(pathName, mode)
  2447. except Exception, e:
  2448. smbServer.log("SMB2_CREATE: %s,%s,%s" % (pathName,mode,e),logging.ERROR)
  2449. #print e
  2450. fid = 0
  2451. errorCode = STATUS_ACCESS_DENIED
  2452. else:
  2453. errorCode = STATUS_SMB_BAD_TID
  2454. if errorCode == STATUS_SUCCESS:
  2455. # Simple way to generate a fid
  2456. fakefid = uuid.generate()
  2457. respSMBCommand['FileID'] = fakefid
  2458. respSMBCommand['CreateAction'] = createDisposition
  2459. if fid == PIPE_FILE_DESCRIPTOR:
  2460. respSMBCommand['CreationTime'] = 0
  2461. respSMBCommand['LastAccessTime'] = 0
  2462. respSMBCommand['LastWriteTime'] = 0
  2463. respSMBCommand['ChangeTime'] = 0
  2464. respSMBCommand['AllocationSize'] = 4096
  2465. respSMBCommand['EndOfFile'] = 0
  2466. respSMBCommand['FileAttributes'] = 0x80
  2467. else:
  2468. if os.path.isdir(pathName):
  2469. respSMBCommand['FileAttributes'] = smb.SMB_FILE_ATTRIBUTE_DIRECTORY
  2470. else:
  2471. respSMBCommand['FileAttributes'] = ntCreateRequest['FileAttributes']
  2472. # Let's get this file's information
  2473. respInfo, errorCode = queryPathInformation('',pathName,level= smb.SMB_QUERY_FILE_ALL_INFO)
  2474. if errorCode == STATUS_SUCCESS:
  2475. respSMBCommand['CreationTime'] = respInfo['CreationTime']
  2476. respSMBCommand['LastAccessTime'] = respInfo['LastAccessTime']
  2477. respSMBCommand['LastWriteTime'] = respInfo['LastWriteTime']
  2478. respSMBCommand['LastChangeTime'] = respInfo['LastChangeTime']
  2479. respSMBCommand['FileAttributes'] = respInfo['ExtFileAttributes']
  2480. respSMBCommand['AllocationSize'] = respInfo['AllocationSize']
  2481. respSMBCommand['EndOfFile'] = respInfo['EndOfFile']
  2482. if errorCode == STATUS_SUCCESS:
  2483. # Let's store the fid for the connection
  2484. # smbServer.log('Create file %s, mode:0x%x' % (pathName, mode))
  2485. connData['OpenedFiles'][fakefid] = {}
  2486. connData['OpenedFiles'][fakefid]['FileHandle'] = fid
  2487. connData['OpenedFiles'][fakefid]['FileName'] = pathName
  2488. connData['OpenedFiles'][fakefid]['DeleteOnClose'] = deleteOnClose
  2489. connData['OpenedFiles'][fakefid]['Open'] = {}
  2490. connData['OpenedFiles'][fakefid]['Open']['EnumerationLocation'] = 0
  2491. connData['OpenedFiles'][fakefid]['Open']['EnumerationSearchPattern'] = ''
  2492. if fid == PIPE_FILE_DESCRIPTOR:
  2493. connData['OpenedFiles'][fakefid]['Socket'] = sock
  2494. else:
  2495. respSMBCommand = smb2.SMB2Error()
  2496. if errorCode == STATUS_SUCCESS:
  2497. connData['LastRequest']['SMB2_CREATE'] = respSMBCommand
  2498. smbServer.setConnectionData(connId, connData)
  2499. return [respSMBCommand], None, errorCode
  2500. @staticmethod
  2501. def smb2Close(connId, smbServer, recvPacket):
  2502. connData = smbServer.getConnectionData(connId)
  2503. respSMBCommand = smb2.SMB2Close_Response()
  2504. closeRequest = smb2.SMB2Close(recvPacket['Data'])
  2505. if str(closeRequest['FileID']) == '\xff'*16:
  2506. # Let's take the data from the lastRequest
  2507. if connData['LastRequest'].has_key('SMB2_CREATE'):
  2508. fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
  2509. else:
  2510. fileID = str(closeRequest['FileID'])
  2511. else:
  2512. fileID = str(closeRequest['FileID'])
  2513. if connData['OpenedFiles'].has_key(fileID):
  2514. errorCode = STATUS_SUCCESS
  2515. fileHandle = connData['OpenedFiles'][fileID]['FileHandle']
  2516. pathName = connData['OpenedFiles'][fileID]['FileName']
  2517. infoRecord = None
  2518. try:
  2519. if fileHandle == PIPE_FILE_DESCRIPTOR:
  2520. connData['OpenedFiles'][fileID]['Socket'].close()
  2521. elif fileHandle != VOID_FILE_DESCRIPTOR:
  2522. os.close(fileHandle)
  2523. infoRecord, errorCode = queryFileInformation(os.path.dirname(pathName), os.path.basename(pathName), smb2.SMB2_FILE_NETWORK_OPEN_INFO)
  2524. except Exception, e:
  2525. smbServer.log("SMB2_CLOSE %s" % e, logging.ERROR)
  2526. errorCode = STATUS_INVALID_HANDLE
  2527. else:
  2528. # Check if the file was marked for removal
  2529. if connData['OpenedFiles'][fileID]['DeleteOnClose'] is True:
  2530. try:
  2531. if os.path.isdir(pathName):
  2532. shutil.rmtree(connData['OpenedFiles'][fileID]['FileName'])
  2533. else:
  2534. os.remove(connData['OpenedFiles'][fileID]['FileName'])
  2535. except Exception, e:
  2536. smbServer.log("SMB2_CLOSE %s" % e, logging.ERROR)
  2537. errorCode = STATUS_ACCESS_DENIED
  2538. # Now fill out the response
  2539. if infoRecord is not None:
  2540. respSMBCommand['CreationTime'] = infoRecord['CreationTime']
  2541. respSMBCommand['LastAccessTime'] = infoRecord['LastAccessTime']
  2542. respSMBCommand['LastWriteTime'] = infoRecord['LastWriteTime']
  2543. respSMBCommand['ChangeTime'] = infoRecord['ChangeTime']
  2544. respSMBCommand['AllocationSize'] = infoRecord['AllocationSize']
  2545. respSMBCommand['EndofFile'] = infoRecord['EndOfFile']
  2546. respSMBCommand['FileAttributes'] = infoRecord['FileAttributes']
  2547. if errorCode == STATUS_SUCCESS:
  2548. del(connData['OpenedFiles'][fileID])
  2549. else:
  2550. errorCode = STATUS_INVALID_HANDLE
  2551. smbServer.setConnectionData(connId, connData)
  2552. return [respSMBCommand], None, errorCode
  2553. @staticmethod
  2554. def smb2QueryInfo(connId, smbServer, recvPacket):
  2555. connData = smbServer.getConnectionData(connId)
  2556. respSMBCommand = smb2.SMB2QueryInfo_Response()
  2557. queryInfo = smb2.SMB2QueryInfo(recvPacket['Data'])
  2558. errorCode = STATUS_SUCCESS
  2559. respSMBCommand['OutputBufferOffset'] = 0x48
  2560. respSMBCommand['Buffer'] = '\x00'
  2561. if str(queryInfo['FileID']) == '\xff'*16:
  2562. # Let's take the data from the lastRequest
  2563. if connData['LastRequest'].has_key('SMB2_CREATE'):
  2564. fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
  2565. else:
  2566. fileID = str(queryInfo['FileID'])
  2567. else:
  2568. fileID = str(queryInfo['FileID'])
  2569. if connData['ConnectedShares'].has_key(recvPacket['TreeID']):
  2570. if connData['OpenedFiles'].has_key(fileID):
  2571. fileName = connData['OpenedFiles'][fileID]['FileName']
  2572. if queryInfo['InfoType'] == smb2.SMB2_0_INFO_FILE:
  2573. if queryInfo['FileInfoClass'] == smb2.SMB2_FILE_INTERNAL_INFO:
  2574. # No need to call queryFileInformation, we have the data here
  2575. infoRecord = smb2.FileInternalInformation()
  2576. infoRecord['IndexNumber'] = fileID
  2577. else:
  2578. infoRecord, errorCode = queryFileInformation(os.path.dirname(fileName), os.path.basename(fileName), queryInfo['FileInfoClass'])
  2579. elif queryInfo['InfoType'] == smb2.SMB2_0_INFO_FILESYSTEM:
  2580. infoRecord = queryFsInformation(os.path.dirname(fileName), os.path.basename(fileName), queryInfo['FileInfoClass'])
  2581. elif queryInfo['InfoType'] == smb2.SMB2_0_INFO_SECURITY:
  2582. # Failing for now, until we support it
  2583. infoRecord = None
  2584. errorCode = STATUS_ACCESS_DENIED
  2585. else:
  2586. smbServer.log("queryInfo not supported (%x)" % queryInfo['InfoType'], logging.ERROR)
  2587. if infoRecord is not None:
  2588. respSMBCommand['OutputBufferLength'] = len(infoRecord)
  2589. respSMBCommand['Buffer'] = infoRecord
  2590. else:
  2591. errorCode = STATUS_INVALID_HANDLE
  2592. else:
  2593. errorCode = STATUS_SMB_BAD_TID
  2594. smbServer.setConnectionData(connId, connData)
  2595. return [respSMBCommand], None, errorCode
  2596. @staticmethod
  2597. def smb2SetInfo(connId, smbServer, recvPacket):
  2598. connData = smbServer.getConnectionData(connId)
  2599. respSMBCommand = smb2.SMB2SetInfo_Response()
  2600. setInfo = smb2.SMB2SetInfo(recvPacket['Data'])
  2601. errorCode = STATUS_SUCCESS
  2602. if str(setInfo['FileID']) == '\xff'*16:
  2603. # Let's take the data from the lastRequest
  2604. if connData['LastRequest'].has_key('SMB2_CREATE'):
  2605. fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
  2606. else:
  2607. fileID = str(setInfo['FileID'])
  2608. else:
  2609. fileID = str(setInfo['FileID'])
  2610. if connData['ConnectedShares'].has_key(recvPacket['TreeID']):
  2611. path = connData['ConnectedShares'][recvPacket['TreeID']]['path']
  2612. if connData['OpenedFiles'].has_key(fileID):
  2613. pathName = connData['OpenedFiles'][fileID]['FileName']
  2614. if setInfo['InfoType'] == smb2.SMB2_0_INFO_FILE:
  2615. # The file information is being set
  2616. informationLevel = setInfo['FileInfoClass']
  2617. if informationLevel == smb2.SMB2_FILE_DISPOSITION_INFO:
  2618. infoRecord = smb.SMBSetFileDispositionInfo(setInfo['Buffer'])
  2619. if infoRecord['DeletePending'] > 0:
  2620. # Mark this file for removal after closed
  2621. connData['OpenedFiles'][fileID]['DeleteOnClose'] = True
  2622. elif informationLevel == smb2.SMB2_FILE_BASIC_INFO:
  2623. infoRecord = smb.SMBSetFileBasicInfo(setInfo['Buffer'])
  2624. # Creation time won't be set, the other ones we play with.
  2625. atime = infoRecord['LastWriteTime']
  2626. if atime == 0:
  2627. atime = -1
  2628. else:
  2629. atime = getUnixTime(atime)
  2630. mtime = infoRecord['ChangeTime']
  2631. if mtime == 0:
  2632. mtime = -1
  2633. else:
  2634. mtime = getUnixTime(mtime)
  2635. if atime > 0 and mtime > 0:
  2636. os.utime(pathName,(atime,mtime))
  2637. elif informationLevel == smb2.SMB2_FILE_END_OF_FILE_INFO:
  2638. fileHandle = connData['OpenedFiles'][fileID]['FileHandle']
  2639. infoRecord = smb.SMBSetFileEndOfFileInfo(setInfo['Buffer'])
  2640. if infoRecord['EndOfFile'] > 0:
  2641. os.lseek(fileHandle, infoRecord['EndOfFile']-1, 0)
  2642. os.write(fileHandle, '\x00')
  2643. elif informationLevel == smb2.SMB2_FILE_RENAME_INFO:
  2644. renameInfo = smb2.FILE_RENAME_INFORMATION_TYPE_2(setInfo['Buffer'])
  2645. newPathName = os.path.join(path,renameInfo['FileName'].decode('utf-16le').replace('\\', '/'))
  2646. if renameInfo['ReplaceIfExists'] == 0 and os.path.exists(newPathName):
  2647. return [smb2.SMB2Error()], None, STATUS_OBJECT_NAME_COLLISION
  2648. try:
  2649. os.rename(pathName,newPathName)
  2650. connData['OpenedFiles'][fileID]['FileName'] = newPathName
  2651. except Exception, e:
  2652. smbServer.log("smb2SetInfo: %s" % e, logging.ERROR)
  2653. errorCode = STATUS_ACCESS_DENIED
  2654. else:
  2655. smbServer.log('Unknown level for set file info! 0x%x' % informationLevel, logging.ERROR)
  2656. # UNSUPPORTED
  2657. errorCode = STATUS_NOT_SUPPORTED
  2658. #elif setInfo['InfoType'] == smb2.SMB2_0_INFO_FILESYSTEM:
  2659. # # The underlying object store information is being set.
  2660. # setInfo = queryFsInformation('/', fileName, queryInfo['FileInfoClass'])
  2661. #elif setInfo['InfoType'] == smb2.SMB2_0_INFO_SECURITY:
  2662. # # The security information is being set.
  2663. # # Failing for now, until we support it
  2664. # infoRecord = None
  2665. # errorCode = STATUS_ACCESS_DENIED
  2666. #elif setInfo['InfoType'] == smb2.SMB2_0_INFO_QUOTA:
  2667. # # The underlying object store quota information is being set.
  2668. # setInfo = queryFsInformation('/', fileName, queryInfo['FileInfoClass'])
  2669. else:
  2670. smbServer.log("setInfo not supported (%x)" % setInfo['InfoType'], logging.ERROR)
  2671. else:
  2672. errorCode = STATUS_INVALID_HANDLE
  2673. else:
  2674. errorCode = STATUS_SMB_BAD_TID
  2675. smbServer.setConnectionData(connId, connData)
  2676. return [respSMBCommand], None, errorCode
  2677. @staticmethod
  2678. def smb2Write(connId, smbServer, recvPacket):
  2679. connData = smbServer.getConnectionData(connId)
  2680. respSMBCommand = smb2.SMB2Write_Response()
  2681. writeRequest = smb2.SMB2Write(recvPacket['Data'])
  2682. respSMBCommand['Buffer'] = '\x00'
  2683. if str(writeRequest['FileID']) == '\xff'*16:
  2684. # Let's take the data from the lastRequest
  2685. if connData['LastRequest'].has_key('SMB2_CREATE'):
  2686. fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
  2687. else:
  2688. fileID = str(writeRequest['FileID'])
  2689. else:
  2690. fileID = str(writeRequest['FileID'])
  2691. if connData['OpenedFiles'].has_key(fileID):
  2692. fileHandle = connData['OpenedFiles'][fileID]['FileHandle']
  2693. errorCode = STATUS_SUCCESS
  2694. try:
  2695. if fileHandle != PIPE_FILE_DESCRIPTOR:
  2696. offset = writeRequest['Offset']
  2697. # If we're trying to write past the file end we just skip the write call (Vista does this)
  2698. if os.lseek(fileHandle, 0, 2) >= offset:
  2699. os.lseek(fileHandle,offset,0)
  2700. os.write(fileHandle,writeRequest['Buffer'])
  2701. else:
  2702. sock = connData['OpenedFiles'][fileID]['Socket']
  2703. sock.send(writeRequest['Buffer'])
  2704. respSMBCommand['Count'] = writeRequest['Length']
  2705. respSMBCommand['Remaining']= 0xff
  2706. except Exception, e:
  2707. smbServer.log('SMB2_WRITE: %s' % e, logging.ERROR)
  2708. errorCode = STATUS_ACCESS_DENIED
  2709. else:
  2710. errorCode = STATUS_INVALID_HANDLE
  2711. smbServer.setConnectionData(connId, connData)
  2712. return [respSMBCommand], None, errorCode
  2713. @staticmethod
  2714. def smb2Read(connId, smbServer, recvPacket):
  2715. connData = smbServer.getConnectionData(connId)
  2716. respSMBCommand = smb2.SMB2Read_Response()
  2717. readRequest = smb2.SMB2Read(recvPacket['Data'])
  2718. respSMBCommand['Buffer'] = '\x00'
  2719. if str(readRequest['FileID']) == '\xff'*16:
  2720. # Let's take the data from the lastRequest
  2721. if connData['LastRequest'].has_key('SMB2_CREATE'):
  2722. fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
  2723. else:
  2724. fileID = str(readRequest['FileID'])
  2725. else:
  2726. fileID = str(readRequest['FileID'])
  2727. if connData['OpenedFiles'].has_key(fileID):
  2728. fileHandle = connData['OpenedFiles'][fileID]['FileHandle']
  2729. errorCode = 0
  2730. try:
  2731. if fileHandle != PIPE_FILE_DESCRIPTOR:
  2732. offset = readRequest['Offset']
  2733. os.lseek(fileHandle,offset,0)
  2734. content = os.read(fileHandle,readRequest['Length'])
  2735. else:
  2736. sock = connData['OpenedFiles'][fileID]['Socket']
  2737. content = sock.recv(readRequest['Length'])
  2738. respSMBCommand['DataOffset'] = 0x50
  2739. respSMBCommand['DataLength'] = len(content)
  2740. respSMBCommand['DataRemaining']= 0
  2741. respSMBCommand['Buffer'] = content
  2742. except Exception, e:
  2743. smbServer.log('SMB2_READ: %s ' % e, logging.ERROR)
  2744. errorCode = STATUS_ACCESS_DENIED
  2745. else:
  2746. errorCode = STATUS_INVALID_HANDLE
  2747. smbServer.setConnectionData(connId, connData)
  2748. return [respSMBCommand], None, errorCode
  2749. @staticmethod
  2750. def smb2Flush(connId, smbServer, recvPacket):
  2751. connData = smbServer.getConnectionData(connId)
  2752. respSMBCommand = smb2.SMB2Flush_Response()
  2753. flushRequest = smb2.SMB2Flush(recvPacket['Data'])
  2754. if connData['OpenedFiles'].has_key(str(flushRequest['FileID'])):
  2755. fileHandle = connData['OpenedFiles'][str(flushRequest['FileID'])]['FileHandle']
  2756. errorCode = STATUS_SUCCESS
  2757. try:
  2758. os.fsync(fileHandle)
  2759. except Exception, e:
  2760. smbServer.log("SMB2_FLUSH %s" % e, logging.ERROR)
  2761. errorCode = STATUS_ACCESS_DENIED
  2762. else:
  2763. errorCode = STATUS_INVALID_HANDLE
  2764. smbServer.setConnectionData(connId, connData)
  2765. return [respSMBCommand], None, errorCode
  2766. @staticmethod
  2767. def smb2QueryDirectory(connId, smbServer, recvPacket):
  2768. connData = smbServer.getConnectionData(connId)
  2769. respSMBCommand = smb2.SMB2QueryDirectory_Response()
  2770. queryDirectoryRequest = smb2.SMB2QueryDirectory(recvPacket['Data'])
  2771. respSMBCommand['Buffer'] = '\x00'
  2772. # The server MUST locate the tree connection, as specified in section 3.3.5.2.11.
  2773. if connData['ConnectedShares'].has_key(recvPacket['TreeID']) is False:
  2774. return [smb2.SMB2Error()], None, STATUS_NETWORK_NAME_DELETED
  2775. # Next, the server MUST locate the open for the directory to be queried
  2776. # If no open is found, the server MUST fail the request with STATUS_FILE_CLOSED
  2777. if str(queryDirectoryRequest['FileID']) == '\xff'*16:
  2778. # Let's take the data from the lastRequest
  2779. if connData['LastRequest'].has_key('SMB2_CREATE'):
  2780. fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
  2781. else:
  2782. fileID = str(queryDirectoryRequest['FileID'])
  2783. else:
  2784. fileID = str(queryDirectoryRequest['FileID'])
  2785. if connData['OpenedFiles'].has_key(fileID) is False:
  2786. return [smb2.SMB2Error()], None, STATUS_FILE_CLOSED
  2787. # If the open is not an open to a directory, the request MUST be failed
  2788. # with STATUS_INVALID_PARAMETER.
  2789. if os.path.isdir(connData['OpenedFiles'][fileID]['FileName']) is False:
  2790. return [smb2.SMB2Error()], None, STATUS_INVALID_PARAMETER
  2791. # If any other information class is specified in the FileInformationClass
  2792. # field of the SMB2 QUERY_DIRECTORY Request, the server MUST fail the
  2793. # operation with STATUS_INVALID_INFO_CLASS.
  2794. if queryDirectoryRequest['FileInformationClass'] not in (
  2795. smb2.FILE_DIRECTORY_INFORMATION, smb2.FILE_FULL_DIRECTORY_INFORMATION, smb2.FILEID_FULL_DIRECTORY_INFORMATION,
  2796. smb2.FILE_BOTH_DIRECTORY_INFORMATION, smb2.FILEID_BOTH_DIRECTORY_INFORMATION, smb2.FILENAMES_INFORMATION):
  2797. return [smb2.SMB2Error()], None, STATUS_INVALID_INFO_CLASS
  2798. # If SMB2_REOPEN is set in the Flags field of the SMB2 QUERY_DIRECTORY
  2799. # Request, the server SHOULD<326> set Open.EnumerationLocation to 0
  2800. # and Open.EnumerationSearchPattern to an empty string.
  2801. if queryDirectoryRequest['Flags'] & smb2.SMB2_REOPEN:
  2802. connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] = 0
  2803. connData['OpenedFiles'][fileID]['Open']['EnumerationSearchPattern'] = ''
  2804. # If SMB2_RESTART_SCANS is set in the Flags field of the SMB2
  2805. # QUERY_DIRECTORY Request, the server MUST set
  2806. # Open.EnumerationLocation to 0.
  2807. if queryDirectoryRequest['Flags'] & smb2.SMB2_RESTART_SCANS:
  2808. connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] = 0
  2809. # If Open.EnumerationLocation is 0 and Open.EnumerationSearchPattern
  2810. # is an empty string, then Open.EnumerationSearchPattern MUST be set
  2811. # to the search pattern specified in the SMB2 QUERY_DIRECTORY by
  2812. # FileNameOffset and FileNameLength. If FileNameLength is 0, the server
  2813. # SHOULD<327> set Open.EnumerationSearchPattern as "*" to search all entries.
  2814. pattern = queryDirectoryRequest['Buffer'].decode('utf-16le')
  2815. if connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] == 0 and \
  2816. connData['OpenedFiles'][fileID]['Open']['EnumerationSearchPattern'] == '':
  2817. if pattern == '':
  2818. pattern = '*'
  2819. connData['OpenedFiles'][fileID]['Open']['EnumerationSearchPattern'] = pattern
  2820. # If SMB2_INDEX_SPECIFIED is set and FileNameLength is not zero,
  2821. # the server MUST set Open.EnumerationSearchPattern to the search pattern
  2822. # specified in the request by FileNameOffset and FileNameLength.
  2823. if queryDirectoryRequest['Flags'] & smb2.SMB2_INDEX_SPECIFIED and \
  2824. queryDirectoryRequest['FileNameLength'] > 0:
  2825. connData['OpenedFiles'][fileID]['Open']['EnumerationSearchPattern'] = pattern
  2826. pathName = os.path.join(os.path.normpath(connData['OpenedFiles'][fileID]['FileName']),pattern)
  2827. searchResult, searchCount, errorCode = findFirst2(os.path.dirname(pathName),
  2828. os.path.basename(pathName),
  2829. queryDirectoryRequest['FileInformationClass'],
  2830. smb.ATTR_DIRECTORY, isSMB2 = True )
  2831. if errorCode != STATUS_SUCCESS:
  2832. return [smb2.SMB2Error()], None, errorCode
  2833. if searchCount > 2 and pattern == '*':
  2834. # strip . and ..
  2835. searchCount -= 2
  2836. searchResult = searchResult[2:]
  2837. if searchCount == 0 and connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] == 0:
  2838. return [smb2.SMB2Error()], None, STATUS_NO_SUCH_FILE
  2839. if connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] < 0:
  2840. return [smb2.SMB2Error()], None, STATUS_NO_MORE_FILES
  2841. totalData = 0
  2842. respData = ''
  2843. for nItem in range(connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'], searchCount):
  2844. connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] += 1
  2845. if queryDirectoryRequest['Flags'] & smb2.SL_RETURN_SINGLE_ENTRY:
  2846. # If single entry is requested we must clear the NextEntryOffset
  2847. searchResult[nItem]['NextEntryOffset'] = 0
  2848. data = searchResult[nItem].getData()
  2849. lenData = len(data)
  2850. padLen = (8-(lenData % 8)) %8
  2851. if (totalData+lenData) >= queryDirectoryRequest['OutputBufferLength']:
  2852. connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] -= 1
  2853. break
  2854. else:
  2855. respData += data + '\x00'*padLen
  2856. totalData += lenData + padLen
  2857. if queryDirectoryRequest['Flags'] & smb2.SL_RETURN_SINGLE_ENTRY:
  2858. break
  2859. if connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] >= searchCount:
  2860. connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] = -1
  2861. respSMBCommand['OutputBufferOffset'] = 0x48
  2862. respSMBCommand['OutputBufferLength'] = totalData
  2863. respSMBCommand['Buffer'] = respData
  2864. smbServer.setConnectionData(connId, connData)
  2865. return [respSMBCommand], None, errorCode
  2866. @staticmethod
  2867. def smb2ChangeNotify(connId, smbServer, recvPacket):
  2868. return [smb2.SMB2Error()], None, STATUS_NOT_SUPPORTED
  2869. @staticmethod
  2870. def smb2Echo(connId, smbServer, recvPacket):
  2871. respSMBCommand = smb2.SMB2Echo_Response()
  2872. return [respSMBCommand], None, STATUS_SUCCESS
  2873. @staticmethod
  2874. def smb2TreeDisconnect(connId, smbServer, recvPacket):
  2875. connData = smbServer.getConnectionData(connId)
  2876. respSMBCommand = smb2.SMB2TreeDisconnect_Response()
  2877. if connData['ConnectedShares'].has_key(recvPacket['TreeID']):
  2878. smbServer.log("Disconnecting Share(%d:%s)" % (recvPacket['TreeID'],connData['ConnectedShares'][recvPacket['TreeID']]['shareName']))
  2879. del(connData['ConnectedShares'][recvPacket['TreeID']])
  2880. errorCode = STATUS_SUCCESS
  2881. else:
  2882. # STATUS_SMB_BAD_TID
  2883. errorCode = STATUS_SMB_BAD_TID
  2884. smbServer.setConnectionData(connId, connData)
  2885. return [respSMBCommand], None, errorCode
  2886. @staticmethod
  2887. def smb2Logoff(connId, smbServer, recvPacket):
  2888. connData = smbServer.getConnectionData(connId)
  2889. respSMBCommand = smb2.SMB2Logoff_Response()
  2890. if recvPacket['SessionID'] != connData['Uid']:
  2891. # STATUS_SMB_BAD_UID
  2892. errorCode = STATUS_SMB_BAD_UID
  2893. else:
  2894. errorCode = STATUS_SUCCESS
  2895. connData['Uid'] = 0
  2896. smbServer.setConnectionData(connId, connData)
  2897. return [respSMBCommand], None, errorCode
  2898. @staticmethod
  2899. def smb2Ioctl(connId, smbServer, recvPacket):
  2900. connData = smbServer.getConnectionData(connId)
  2901. respSMBCommand = smb2.SMB2Ioctl_Response()
  2902. ioctlRequest = smb2.SMB2Ioctl(recvPacket['Data'])
  2903. ioctls = smbServer.getIoctls()
  2904. if ioctls.has_key(ioctlRequest['CtlCode']):
  2905. outputData, errorCode = ioctls[ioctlRequest['CtlCode']](connId, smbServer, ioctlRequest)
  2906. if errorCode == STATUS_SUCCESS:
  2907. respSMBCommand['CtlCode'] = ioctlRequest['CtlCode']
  2908. respSMBCommand['FileID'] = ioctlRequest['FileID']
  2909. respSMBCommand['InputOffset'] = 0
  2910. respSMBCommand['InputCount'] = 0
  2911. respSMBCommand['OutputOffset'] = 0x70
  2912. respSMBCommand['OutputCount'] = len(outputData)
  2913. respSMBCommand['Flags'] = 0
  2914. respSMBCommand['Buffer'] = outputData
  2915. else:
  2916. respSMBCommand = outputData
  2917. else:
  2918. smbServer.log("Ioctl not implemented command: 0x%x" % ioctlRequest['CtlCode'],logging.DEBUG)
  2919. errorCode = STATUS_INVALID_DEVICE_REQUEST
  2920. respSMBCommand = smb2.SMB2Error()
  2921. smbServer.setConnectionData(connId, connData)
  2922. return [respSMBCommand], None, errorCode
  2923. @staticmethod
  2924. def smb2Lock(connId, smbServer, recvPacket):
  2925. connData = smbServer.getConnectionData(connId)
  2926. respSMBCommand = smb2.SMB2Lock_Response()
  2927. # I'm actually doing nothing.. just make MacOS happy ;)
  2928. errorCode = STATUS_SUCCESS
  2929. smbServer.setConnectionData(connId, connData)
  2930. return [respSMBCommand], None, errorCode
  2931. @staticmethod
  2932. def smb2Cancel(connId, smbServer, recvPacket):
  2933. # I'm actually doing nothing
  2934. return [smb2.SMB2Error()], None, STATUS_CANCELLED
  2935. @staticmethod
  2936. def default(connId, smbServer, recvPacket):
  2937. # By default we return an SMB Packet with error not implemented
  2938. smbServer.log("Not implemented command: 0x%x" % recvPacket['Command'],logging.DEBUG)
  2939. return [smb2.SMB2Error()], None, STATUS_NOT_SUPPORTED
  2940. class Ioctls:
  2941. @staticmethod
  2942. def fsctlDfsGetReferrals(connId, smbServer, ioctlRequest):
  2943. return smb2.SMB2Error(), STATUS_FS_DRIVER_REQUIRED
  2944. @staticmethod
  2945. def fsctlPipeTransceive(connId, smbServer, ioctlRequest):
  2946. connData = smbServer.getConnectionData(connId)
  2947. ioctlResponse = ''
  2948. if connData['OpenedFiles'].has_key(str(ioctlRequest['FileID'])):
  2949. fileHandle = connData['OpenedFiles'][str(ioctlRequest['FileID'])]['FileHandle']
  2950. errorCode = STATUS_SUCCESS
  2951. try:
  2952. if fileHandle != PIPE_FILE_DESCRIPTOR:
  2953. errorCode = STATUS_INVALID_DEVICE_REQUEST
  2954. else:
  2955. sock = connData['OpenedFiles'][str(ioctlRequest['FileID'])]['Socket']
  2956. sock.sendall(ioctlRequest['Buffer'])
  2957. ioctlResponse = sock.recv(ioctlRequest['MaxOutputResponse'])
  2958. except Exception, e:
  2959. smbServer.log('fsctlPipeTransceive: %s ' % e, logging.ERROR)
  2960. errorCode = STATUS_ACCESS_DENIED
  2961. else:
  2962. errorCode = STATUS_INVALID_DEVICE_REQUEST
  2963. smbServer.setConnectionData(connId, connData)
  2964. return ioctlResponse, errorCode
  2965. @staticmethod
  2966. def fsctlValidateNegotiateInfo(connId, smbServer, ioctlRequest):
  2967. connData = smbServer.getConnectionData(connId)
  2968. errorCode = STATUS_SUCCESS
  2969. validateNegotiateInfo = smb2.VALIDATE_NEGOTIATE_INFO(ioctlRequest['Buffer'])
  2970. validateNegotiateInfo['Capabilities'] = 0
  2971. validateNegotiateInfo['Guid'] = 'A'*16
  2972. validateNegotiateInfo['SecurityMode'] = 1
  2973. validateNegotiateInfo['Dialects'] = (smb2.SMB2_DIALECT_002,)
  2974. smbServer.setConnectionData(connId, connData)
  2975. return validateNegotiateInfo.getData(), errorCode
  2976. class SMBSERVERHandler(SocketServer.BaseRequestHandler):
  2977. def __init__(self, request, client_address, server, select_poll = False):
  2978. self.__SMB = server
  2979. self.__ip, self.__port = client_address
  2980. self.__request = request
  2981. self.__connId = threading.currentThread().getName()
  2982. self.__timeOut = 60*5
  2983. self.__select_poll = select_poll
  2984. #self.__connId = os.getpid()
  2985. SocketServer.BaseRequestHandler.__init__(self, request, client_address, server)
  2986. def handle(self):
  2987. self.__SMB.log("Incoming connection (%s,%d)" % (self.__ip, self.__port))
  2988. self.__SMB.addConnection(self.__connId, self.__ip, self.__port)
  2989. while True:
  2990. try:
  2991. # Firt of all let's get the NETBIOS packet
  2992. session = nmb.NetBIOSTCPSession(self.__SMB.getServerName(),'HOST', self.__ip, sess_port = self.__port, sock = self.__request, select_poll = self.__select_poll)
  2993. try:
  2994. p = session.recv_packet(self.__timeOut)
  2995. except nmb.NetBIOSTimeout:
  2996. raise
  2997. except nmb.NetBIOSError:
  2998. break
  2999. if p.get_type() == nmb.NETBIOS_SESSION_REQUEST:
  3000. # Someone is requesting a session, we're gonna accept them all :)
  3001. _, rn, my = p.get_trailer().split(' ')
  3002. remote_name = nmb.decode_name('\x20'+rn)
  3003. myname = nmb.decode_name('\x20'+my)
  3004. self.__SMB.log("NetBIOS Session request (%s,%s,%s)" % (self.__ip, remote_name[1].strip(), myname[1]))
  3005. r = nmb.NetBIOSSessionPacket()
  3006. r.set_type(nmb.NETBIOS_SESSION_POSITIVE_RESPONSE)
  3007. r.set_trailer(p.get_trailer())
  3008. self.__request.send(r.rawData())
  3009. else:
  3010. resp = self.__SMB.processRequest(self.__connId, p.get_trailer())
  3011. # Send all the packets recevied. Except for big transactions this should be
  3012. # a single packet
  3013. for i in resp:
  3014. session.send_packet(str(i))
  3015. except Exception, e:
  3016. self.__SMB.log("Handle: %s" % e)
  3017. #import traceback
  3018. #traceback.print_exc()
  3019. break
  3020. def finish(self):
  3021. # Thread/process is dying, we should tell the main SMB thread to remove all this thread data
  3022. self.__SMB.log("Closing down connection (%s,%d)" % (self.__ip, self.__port))
  3023. self.__SMB.removeConnection(self.__connId)
  3024. return SocketServer.BaseRequestHandler.finish(self)
  3025. class SMBSERVER(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
  3026. #class SMBSERVER(SocketServer.ForkingMixIn, SocketServer.TCPServer):
  3027. def __init__(self, server_address, handler_class=SMBSERVERHandler, config_parser = None):
  3028. SocketServer.TCPServer.allow_reuse_address = True
  3029. SocketServer.TCPServer.__init__(self, server_address, handler_class)
  3030. # Server name and OS to be presented whenever is necessary
  3031. self.__serverName = ''
  3032. self.__serverOS = ''
  3033. self.__serverDomain = ''
  3034. self.__challenge = ''
  3035. self.__log = None
  3036. # Our ConfigParser data
  3037. self.__serverConfig = config_parser
  3038. # Our credentials to be used during the server's lifetime
  3039. self.__credentials = {}
  3040. # Our log file
  3041. self.__logFile = ''
  3042. # Registered Named Pipes, format is PipeName,Socket
  3043. self.__registeredNamedPipes = {}
  3044. # JTR dump path
  3045. self.__jtr_dump_path = ''
  3046. # SMB2 Support flag = default not active
  3047. self.__SMB2Support = False
  3048. # Our list of commands we will answer, by default the NOT IMPLEMENTED one
  3049. self.__smbCommandsHandler = SMBCommands()
  3050. self.__smbTrans2Handler = TRANS2Commands()
  3051. self.__smbTransHandler = TRANSCommands()
  3052. self.__smbNTTransHandler = NTTRANSCommands()
  3053. self.__smb2CommandsHandler = SMB2Commands()
  3054. self.__IoctlHandler = Ioctls()
  3055. self.__smbNTTransCommands = {
  3056. # NT IOCTL, can't find doc for this
  3057. 0xff :self.__smbNTTransHandler.default
  3058. }
  3059. self.__smbTransCommands = {
  3060. '\\PIPE\\LANMAN' :self.__smbTransHandler.lanMan,
  3061. smb.SMB.TRANS_TRANSACT_NMPIPE :self.__smbTransHandler.transactNamedPipe,
  3062. }
  3063. self.__smbTrans2Commands = {
  3064. smb.SMB.TRANS2_FIND_FIRST2 :self.__smbTrans2Handler.findFirst2,
  3065. smb.SMB.TRANS2_FIND_NEXT2 :self.__smbTrans2Handler.findNext2,
  3066. smb.SMB.TRANS2_QUERY_FS_INFORMATION :self.__smbTrans2Handler.queryFsInformation,
  3067. smb.SMB.TRANS2_QUERY_PATH_INFORMATION :self.__smbTrans2Handler.queryPathInformation,
  3068. smb.SMB.TRANS2_QUERY_FILE_INFORMATION :self.__smbTrans2Handler.queryFileInformation,
  3069. smb.SMB.TRANS2_SET_FILE_INFORMATION :self.__smbTrans2Handler.setFileInformation,
  3070. smb.SMB.TRANS2_SET_PATH_INFORMATION :self.__smbTrans2Handler.setPathInformation
  3071. }
  3072. self.__smbCommands = {
  3073. #smb.SMB.SMB_COM_FLUSH: self.__smbCommandsHandler.smbComFlush,
  3074. smb.SMB.SMB_COM_CREATE_DIRECTORY: self.__smbCommandsHandler.smbComCreateDirectory,
  3075. smb.SMB.SMB_COM_DELETE_DIRECTORY: self.__smbCommandsHandler.smbComDeleteDirectory,
  3076. smb.SMB.SMB_COM_RENAME: self.__smbCommandsHandler.smbComRename,
  3077. smb.SMB.SMB_COM_DELETE: self.__smbCommandsHandler.smbComDelete,
  3078. smb.SMB.SMB_COM_NEGOTIATE: self.__smbCommandsHandler.smbComNegotiate,
  3079. smb.SMB.SMB_COM_SESSION_SETUP_ANDX: self.__smbCommandsHandler.smbComSessionSetupAndX,
  3080. smb.SMB.SMB_COM_LOGOFF_ANDX: self.__smbCommandsHandler.smbComLogOffAndX,
  3081. smb.SMB.SMB_COM_TREE_CONNECT_ANDX: self.__smbCommandsHandler.smbComTreeConnectAndX,
  3082. smb.SMB.SMB_COM_TREE_DISCONNECT: self.__smbCommandsHandler.smbComTreeDisconnect,
  3083. smb.SMB.SMB_COM_ECHO: self.__smbCommandsHandler.smbComEcho,
  3084. smb.SMB.SMB_COM_QUERY_INFORMATION: self.__smbCommandsHandler.smbQueryInformation,
  3085. smb.SMB.SMB_COM_TRANSACTION2: self.__smbCommandsHandler.smbTransaction2,
  3086. smb.SMB.SMB_COM_TRANSACTION: self.__smbCommandsHandler.smbTransaction,
  3087. # Not needed for now
  3088. smb.SMB.SMB_COM_NT_TRANSACT: self.__smbCommandsHandler.smbNTTransact,
  3089. smb.SMB.SMB_COM_QUERY_INFORMATION_DISK: self.__smbCommandsHandler.smbQueryInformationDisk,
  3090. smb.SMB.SMB_COM_OPEN_ANDX: self.__smbCommandsHandler.smbComOpenAndX,
  3091. smb.SMB.SMB_COM_QUERY_INFORMATION2: self.__smbCommandsHandler.smbComQueryInformation2,
  3092. smb.SMB.SMB_COM_READ_ANDX: self.__smbCommandsHandler.smbComReadAndX,
  3093. smb.SMB.SMB_COM_READ: self.__smbCommandsHandler.smbComRead,
  3094. smb.SMB.SMB_COM_WRITE_ANDX: self.__smbCommandsHandler.smbComWriteAndX,
  3095. smb.SMB.SMB_COM_WRITE: self.__smbCommandsHandler.smbComWrite,
  3096. smb.SMB.SMB_COM_CLOSE: self.__smbCommandsHandler.smbComClose,
  3097. smb.SMB.SMB_COM_LOCKING_ANDX: self.__smbCommandsHandler.smbComLockingAndX,
  3098. smb.SMB.SMB_COM_NT_CREATE_ANDX: self.__smbCommandsHandler.smbComNtCreateAndX,
  3099. 0xFF: self.__smbCommandsHandler.default
  3100. }
  3101. self.__smb2Ioctls = {
  3102. smb2.FSCTL_DFS_GET_REFERRALS: self.__IoctlHandler.fsctlDfsGetReferrals,
  3103. # smb2.FSCTL_PIPE_PEEK: self.__IoctlHandler.fsctlPipePeek,
  3104. # smb2.FSCTL_PIPE_WAIT: self.__IoctlHandler.fsctlPipeWait,
  3105. smb2.FSCTL_PIPE_TRANSCEIVE: self.__IoctlHandler.fsctlPipeTransceive,
  3106. # smb2.FSCTL_SRV_COPYCHUNK: self.__IoctlHandler.fsctlSrvCopyChunk,
  3107. # smb2.FSCTL_SRV_ENUMERATE_SNAPSHOTS: self.__IoctlHandler.fsctlSrvEnumerateSnapshots,
  3108. # smb2.FSCTL_SRV_REQUEST_RESUME_KEY: self.__IoctlHandler.fsctlSrvRequestResumeKey,
  3109. # smb2.FSCTL_SRV_READ_HASH: self.__IoctlHandler.fsctlSrvReadHash,
  3110. # smb2.FSCTL_SRV_COPYCHUNK_WRITE: self.__IoctlHandler.fsctlSrvCopyChunkWrite,
  3111. # smb2.FSCTL_LMR_REQUEST_RESILIENCY: self.__IoctlHandler.fsctlLmrRequestResiliency,
  3112. # smb2.FSCTL_QUERY_NETWORK_INTERFACE_INFO: self.__IoctlHandler.fsctlQueryNetworkInterfaceInfo,
  3113. # smb2.FSCTL_SET_REPARSE_POINT: self.__IoctlHandler.fsctlSetReparsePoint,
  3114. # smb2.FSCTL_DFS_GET_REFERRALS_EX: self.__IoctlHandler.fsctlDfsGetReferralsEx,
  3115. # smb2.FSCTL_FILE_LEVEL_TRIM: self.__IoctlHandler.fsctlFileLevelTrim,
  3116. smb2.FSCTL_VALIDATE_NEGOTIATE_INFO: self.__IoctlHandler.fsctlValidateNegotiateInfo,
  3117. }
  3118. self.__smb2Commands = {
  3119. smb2.SMB2_NEGOTIATE: self.__smb2CommandsHandler.smb2Negotiate,
  3120. smb2.SMB2_SESSION_SETUP: self.__smb2CommandsHandler.smb2SessionSetup,
  3121. smb2.SMB2_LOGOFF: self.__smb2CommandsHandler.smb2Logoff,
  3122. smb2.SMB2_TREE_CONNECT: self.__smb2CommandsHandler.smb2TreeConnect,
  3123. smb2.SMB2_TREE_DISCONNECT: self.__smb2CommandsHandler.smb2TreeDisconnect,
  3124. smb2.SMB2_CREATE: self.__smb2CommandsHandler.smb2Create,
  3125. smb2.SMB2_CLOSE: self.__smb2CommandsHandler.smb2Close,
  3126. smb2.SMB2_FLUSH: self.__smb2CommandsHandler.smb2Flush,
  3127. smb2.SMB2_READ: self.__smb2CommandsHandler.smb2Read,
  3128. smb2.SMB2_WRITE: self.__smb2CommandsHandler.smb2Write,
  3129. smb2.SMB2_LOCK: self.__smb2CommandsHandler.smb2Lock,
  3130. smb2.SMB2_IOCTL: self.__smb2CommandsHandler.smb2Ioctl,
  3131. smb2.SMB2_CANCEL: self.__smb2CommandsHandler.smb2Cancel,
  3132. smb2.SMB2_ECHO: self.__smb2CommandsHandler.smb2Echo,
  3133. smb2.SMB2_QUERY_DIRECTORY: self.__smb2CommandsHandler.smb2QueryDirectory,
  3134. smb2.SMB2_CHANGE_NOTIFY: self.__smb2CommandsHandler.smb2ChangeNotify,
  3135. smb2.SMB2_QUERY_INFO: self.__smb2CommandsHandler.smb2QueryInfo,
  3136. smb2.SMB2_SET_INFO: self.__smb2CommandsHandler.smb2SetInfo,
  3137. # smb2.SMB2_OPLOCK_BREAK: self.__smb2CommandsHandler.smb2SessionSetup,
  3138. 0xFF: self.__smb2CommandsHandler.default
  3139. }
  3140. # List of active connections
  3141. self.__activeConnections = {}
  3142. def getIoctls(self):
  3143. return self.__smb2Ioctls
  3144. def getCredentials(self):
  3145. return self.__credentials
  3146. def removeConnection(self, name):
  3147. try:
  3148. del(self.__activeConnections[name])
  3149. except:
  3150. pass
  3151. self.log("Remaining connections %s" % self.__activeConnections.keys())
  3152. def addConnection(self, name, ip, port):
  3153. self.__activeConnections[name] = {}
  3154. # Let's init with some know stuff we will need to have
  3155. # TODO: Document what's in there
  3156. #print "Current Connections", self.__activeConnections.keys()
  3157. self.__activeConnections[name]['PacketNum'] = 0
  3158. self.__activeConnections[name]['ClientIP'] = ip
  3159. self.__activeConnections[name]['ClientPort'] = port
  3160. self.__activeConnections[name]['Uid'] = 0
  3161. self.__activeConnections[name]['ConnectedShares'] = {}
  3162. self.__activeConnections[name]['OpenedFiles'] = {}
  3163. # SID results for findfirst2
  3164. self.__activeConnections[name]['SIDs'] = {}
  3165. self.__activeConnections[name]['LastRequest'] = {}
  3166. def getActiveConnections(self):
  3167. return self.__activeConnections
  3168. def setConnectionData(self, connId, data):
  3169. self.__activeConnections[connId] = data
  3170. #print "setConnectionData"
  3171. #print self.__activeConnections
  3172. def getConnectionData(self, connId, checkStatus = True):
  3173. conn = self.__activeConnections[connId]
  3174. if checkStatus is True:
  3175. if conn.has_key('Authenticated') is not True:
  3176. # Can't keep going further
  3177. raise Exception("User not Authenticated!")
  3178. return conn
  3179. def getRegisteredNamedPipes(self):
  3180. return self.__registeredNamedPipes
  3181. def registerNamedPipe(self, pipeName, address):
  3182. self.__registeredNamedPipes[unicode(pipeName)] = address
  3183. return True
  3184. def unregisterNamedPipe(self, pipeName):
  3185. if self.__registeredNamedPipes.has_key(pipeName):
  3186. del(self.__registeredNamedPipes[unicode(pipeName)])
  3187. return True
  3188. return False
  3189. def unregisterTransaction(self, transCommand):
  3190. if self.__smbTransCommands.has_key(transCommand):
  3191. del(self.__smbTransCommands[transCommand])
  3192. def hookTransaction(self, transCommand, callback):
  3193. # If you call this function, callback will replace
  3194. # the current Transaction sub command.
  3195. # (don't get confused with the Transaction smbCommand)
  3196. # If the transaction sub command doesn't not exist, it is added
  3197. # If the transaction sub command exists, it returns the original function # replaced
  3198. #
  3199. # callback MUST be declared as:
  3200. # callback(connId, smbServer, recvPacket, parameters, data, maxDataCount=0)
  3201. #
  3202. # WHERE:
  3203. #
  3204. # connId : the connection Id, used to grab/update information about
  3205. # the current connection
  3206. # smbServer : the SMBServer instance available for you to ask
  3207. # configuration data
  3208. # recvPacket : the full SMBPacket that triggered this command
  3209. # parameters : the transaction parameters
  3210. # data : the transaction data
  3211. # maxDataCount: the max amount of data that can be transfered agreed
  3212. # with the client
  3213. #
  3214. # and MUST return:
  3215. # respSetup, respParameters, respData, errorCode
  3216. #
  3217. # WHERE:
  3218. #
  3219. # respSetup: the setup response of the transaction
  3220. # respParameters: the parameters response of the transaction
  3221. # respData: the data reponse of the transaction
  3222. # errorCode: the NT error code
  3223. if self.__smbTransCommands.has_key(transCommand):
  3224. originalCommand = self.__smbTransCommands[transCommand]
  3225. else:
  3226. originalCommand = None
  3227. self.__smbTransCommands[transCommand] = callback
  3228. return originalCommand
  3229. def unregisterTransaction2(self, transCommand):
  3230. if self.__smbTrans2Commands.has_key(transCommand):
  3231. del(self.__smbTrans2Commands[transCommand])
  3232. def hookTransaction2(self, transCommand, callback):
  3233. # Here we should add to __smbTrans2Commands
  3234. # Same description as Transaction
  3235. if self.__smbTrans2Commands.has_key(transCommand):
  3236. originalCommand = self.__smbTrans2Commands[transCommand]
  3237. else:
  3238. originalCommand = None
  3239. self.__smbTrans2Commands[transCommand] = callback
  3240. return originalCommand
  3241. def unregisterNTTransaction(self, transCommand):
  3242. if self.__smbNTTransCommands.has_key(transCommand):
  3243. del(self.__smbNTTransCommands[transCommand])
  3244. def hookNTTransaction(self, transCommand, callback):
  3245. # Here we should add to __smbNTTransCommands
  3246. # Same description as Transaction
  3247. if self.__smbNTTransCommands.has_key(transCommand):
  3248. originalCommand = self.__smbNTTransCommands[transCommand]
  3249. else:
  3250. originalCommand = None
  3251. self.__smbNTTransCommands[transCommand] = callback
  3252. return originalCommand
  3253. def unregisterSmbCommand(self, smbCommand):
  3254. if self.__smbCommands.has_key(smbCommand):
  3255. del(self.__smbCommands[smbCommand])
  3256. def hookSmbCommand(self, smbCommand, callback):
  3257. # Here we should add to self.__smbCommands
  3258. # If you call this function, callback will replace
  3259. # the current smbCommand.
  3260. # If smbCommand doesn't not exist, it is added
  3261. # If SMB command exists, it returns the original function replaced
  3262. #
  3263. # callback MUST be declared as:
  3264. # callback(connId, smbServer, SMBCommand, recvPacket)
  3265. #
  3266. # WHERE:
  3267. #
  3268. # connId : the connection Id, used to grab/update information about
  3269. # the current connection
  3270. # smbServer : the SMBServer instance available for you to ask
  3271. # configuration data
  3272. # SMBCommand: the SMBCommand itself, with its data and parameters.
  3273. # Check smb.py:SMBCommand() for a reference
  3274. # recvPacket: the full SMBPacket that triggered this command
  3275. #
  3276. # and MUST return:
  3277. # <list of respSMBCommands>, <list of packets>, errorCode
  3278. # <list of packets> has higher preference over commands, in case you
  3279. # want to change the whole packet
  3280. # errorCode: the NT error code
  3281. #
  3282. # For SMB_COM_TRANSACTION2, SMB_COM_TRANSACTION and SMB_COM_NT_TRANSACT
  3283. # the callback function is slightly different:
  3284. #
  3285. # callback(connId, smbServer, SMBCommand, recvPacket, transCommands)
  3286. #
  3287. # WHERE:
  3288. #
  3289. # transCommands: a list of transaction subcommands already registered
  3290. #
  3291. if self.__smbCommands.has_key(smbCommand):
  3292. originalCommand = self.__smbCommands[smbCommand]
  3293. else:
  3294. originalCommand = None
  3295. self.__smbCommands[smbCommand] = callback
  3296. return originalCommand
  3297. def unregisterSmb2Command(self, smb2Command):
  3298. if self.__smb2Commands.has_key(smb2Command):
  3299. del(self.__smb2Commands[smb2Command])
  3300. def hookSmb2Command(self, smb2Command, callback):
  3301. if self.__smb2Commands.has_key(smb2Command):
  3302. originalCommand = self.__smb2Commands[smb2Command]
  3303. else:
  3304. originalCommand = None
  3305. self.__smb2Commands[smb2Command] = callback
  3306. return originalCommand
  3307. def log(self, msg, level=logging.INFO):
  3308. self.__log.log(level,msg)
  3309. def getServerName(self):
  3310. return self.__serverName
  3311. def getServerOS(self):
  3312. return self.__serverOS
  3313. def getServerDomain(self):
  3314. return self.__serverDomain
  3315. def getSMBChallenge(self):
  3316. return self.__challenge
  3317. def getServerConfig(self):
  3318. return self.__serverConfig
  3319. def setServerConfig(self, config):
  3320. self.__serverConfig = config
  3321. def getJTRdumpPath(self):
  3322. return self.__jtr_dump_path
  3323. def verify_request(self, request, client_address):
  3324. # TODO: Control here the max amount of processes we want to launch
  3325. # returning False, closes the connection
  3326. return True
  3327. def processRequest(self, connId, data):
  3328. # TODO: Process batched commands.
  3329. isSMB2 = False
  3330. SMBCommand = None
  3331. try:
  3332. packet = smb.NewSMBPacket(data = data)
  3333. SMBCommand = smb.SMBCommand(packet['Data'][0])
  3334. except:
  3335. # Maybe a SMB2 packet?
  3336. packet = smb2.SMB2Packet(data = data)
  3337. isSMB2 = True
  3338. # We might have compound requests
  3339. compoundedPacketsResponse = []
  3340. compoundedPackets = []
  3341. try:
  3342. # Search out list of implemented commands
  3343. # We provide them with:
  3344. # connId : representing the data for this specific connection
  3345. # self : the SMBSERVER if they want to ask data to it
  3346. # SMBCommand : the SMBCommand they are expecting to process
  3347. # packet : the received packet itself, in case they need more data than the actual command
  3348. # Only for Transactions
  3349. # transCommand: a list of transaction subcommands
  3350. # We expect to get:
  3351. # respCommands: a list of answers for the commands processed
  3352. # respPacket : if the commands chose to directly craft packet/s, we use this and not the previous
  3353. # this MUST be a list
  3354. # errorCode : self explanatory
  3355. if isSMB2 is False:
  3356. if packet['Command'] == smb.SMB.SMB_COM_TRANSACTION2:
  3357. respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
  3358. connId,
  3359. self,
  3360. SMBCommand,
  3361. packet,
  3362. self.__smbTrans2Commands)
  3363. elif packet['Command'] == smb.SMB.SMB_COM_NT_TRANSACT:
  3364. respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
  3365. connId,
  3366. self,
  3367. SMBCommand,
  3368. packet,
  3369. self.__smbNTTransCommands)
  3370. elif packet['Command'] == smb.SMB.SMB_COM_TRANSACTION:
  3371. respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
  3372. connId,
  3373. self,
  3374. SMBCommand,
  3375. packet,
  3376. self.__smbTransCommands)
  3377. else:
  3378. if self.__smbCommands.has_key(packet['Command']):
  3379. if self.__SMB2Support is True:
  3380. if packet['Command'] == smb.SMB.SMB_COM_NEGOTIATE:
  3381. try:
  3382. respCommands, respPackets, errorCode = self.__smb2Commands[smb2.SMB2_NEGOTIATE](connId, self, packet, True)
  3383. isSMB2 = True
  3384. except Exception, e:
  3385. self.log('SMB2_NEGOTIATE: %s' % e, logging.ERROR)
  3386. # If something went wrong, let's fallback to SMB1
  3387. respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
  3388. connId,
  3389. self,
  3390. SMBCommand,
  3391. packet)
  3392. #self.__SMB2Support = False
  3393. pass
  3394. else:
  3395. respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
  3396. connId,
  3397. self,
  3398. SMBCommand,
  3399. packet)
  3400. else:
  3401. respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
  3402. connId,
  3403. self,
  3404. SMBCommand,
  3405. packet)
  3406. else:
  3407. respCommands, respPackets, errorCode = self.__smbCommands[255](connId, self, SMBCommand, packet)
  3408. compoundedPacketsResponse.append((respCommands, respPackets, errorCode))
  3409. compoundedPackets.append(packet)
  3410. else:
  3411. done = False
  3412. while not done:
  3413. if self.__smb2Commands.has_key(packet['Command']):
  3414. if self.__SMB2Support is True:
  3415. respCommands, respPackets, errorCode = self.__smb2Commands[packet['Command']](
  3416. connId,
  3417. self,
  3418. packet)
  3419. else:
  3420. respCommands, respPackets, errorCode = self.__smb2Commands[255](connId, self, packet)
  3421. else:
  3422. respCommands, respPackets, errorCode = self.__smb2Commands[255](connId, self, packet)
  3423. # Let's store the result for this compounded packet
  3424. compoundedPacketsResponse.append((respCommands, respPackets, errorCode))
  3425. compoundedPackets.append(packet)
  3426. if packet['NextCommand'] != 0:
  3427. data = data[packet['NextCommand']:]
  3428. packet = smb2.SMB2Packet(data = data)
  3429. else:
  3430. done = True
  3431. except Exception, e:
  3432. #import traceback
  3433. #traceback.print_exc()
  3434. # Something wen't wrong, defaulting to Bad user ID
  3435. self.log('processRequest (0x%x,%s)' % (packet['Command'],e), logging.ERROR)
  3436. raise
  3437. # We prepare the response packet to commands don't need to bother about that.
  3438. connData = self.getConnectionData(connId, False)
  3439. # Force reconnection loop.. This is just a test.. client will send me back credentials :)
  3440. #connData['PacketNum'] += 1
  3441. #if connData['PacketNum'] == 15:
  3442. # connData['PacketNum'] = 0
  3443. # # Something wen't wrong, defaulting to Bad user ID
  3444. # self.log('Sending BAD USER ID!', logging.ERROR)
  3445. # #raise
  3446. # packet['Flags1'] |= smb.SMB.FLAGS1_REPLY
  3447. # packet['Flags2'] = 0
  3448. # errorCode = STATUS_SMB_BAD_UID
  3449. # packet['ErrorCode'] = errorCode >> 16
  3450. # packet['ErrorClass'] = errorCode & 0xff
  3451. # return [packet]
  3452. self.setConnectionData(connId, connData)
  3453. packetsToSend = []
  3454. for packetNum in range(len(compoundedPacketsResponse)):
  3455. respCommands, respPackets, errorCode = compoundedPacketsResponse[packetNum]
  3456. packet = compoundedPackets[packetNum]
  3457. if respPackets is None:
  3458. for respCommand in respCommands:
  3459. if isSMB2 is False:
  3460. respPacket = smb.NewSMBPacket()
  3461. respPacket['Flags1'] = smb.SMB.FLAGS1_REPLY
  3462. # TODO this should come from a per session configuration
  3463. respPacket['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_LONG_NAMES | packet['Flags2'] & smb.SMB.FLAGS2_UNICODE
  3464. #respPacket['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_LONG_NAMES
  3465. #respPacket['Flags1'] = 0x98
  3466. #respPacket['Flags2'] = 0xc807
  3467. respPacket['Tid'] = packet['Tid']
  3468. respPacket['Mid'] = packet['Mid']
  3469. respPacket['Pid'] = packet['Pid']
  3470. respPacket['Uid'] = connData['Uid']
  3471. respPacket['ErrorCode'] = errorCode >> 16
  3472. respPacket['_reserved'] = errorCode >> 8 & 0xff
  3473. respPacket['ErrorClass'] = errorCode & 0xff
  3474. respPacket.addCommand(respCommand)
  3475. packetsToSend.append(respPacket)
  3476. else:
  3477. respPacket = smb2.SMB2Packet()
  3478. respPacket['Flags'] = smb2.SMB2_FLAGS_SERVER_TO_REDIR
  3479. if packetNum > 0:
  3480. respPacket['Flags'] |= smb2.SMB2_FLAGS_RELATED_OPERATIONS
  3481. respPacket['Status'] = errorCode
  3482. respPacket['CreditRequestResponse'] = packet['CreditRequestResponse']
  3483. respPacket['Command'] = packet['Command']
  3484. respPacket['CreditCharge'] = packet['CreditCharge']
  3485. #respPacket['CreditCharge'] = 0
  3486. respPacket['Reserved'] = packet['Reserved']
  3487. respPacket['SessionID'] = connData['Uid']
  3488. respPacket['MessageID'] = packet['MessageID']
  3489. respPacket['TreeID'] = packet['TreeID']
  3490. respPacket['Data'] = str(respCommand)
  3491. packetsToSend.append(respPacket)
  3492. else:
  3493. # The SMBCommand took care of building the packet
  3494. packetsToSend = respPackets
  3495. if isSMB2 is True:
  3496. # Let's build a compound answer
  3497. finalData = ''
  3498. i = 0
  3499. for i in range(len(packetsToSend)-1):
  3500. packet = packetsToSend[i]
  3501. # Align to 8-bytes
  3502. padLen = (8 - (len(packet) % 8) ) % 8
  3503. packet['NextCommand'] = len(packet) + padLen
  3504. finalData += str(packet) + padLen*'\x00'
  3505. # Last one
  3506. finalData += str(packetsToSend[len(packetsToSend)-1])
  3507. packetsToSend = [finalData]
  3508. # We clear the compound requests
  3509. connData['LastRequest'] = {}
  3510. return packetsToSend
  3511. def processConfigFile(self, configFile = None):
  3512. # TODO: Do a real config parser
  3513. if self.__serverConfig is None:
  3514. if configFile is None:
  3515. configFile = 'smb.conf'
  3516. self.__serverConfig = ConfigParser.ConfigParser()
  3517. self.__serverConfig.read(configFile)
  3518. self.__serverName = self.__serverConfig.get('global','server_name')
  3519. self.__serverOS = self.__serverConfig.get('global','server_os')
  3520. self.__serverDomain = self.__serverConfig.get('global','server_domain')
  3521. self.__logFile = self.__serverConfig.get('global','log_file')
  3522. if self.__serverConfig.has_option('global', 'challenge'):
  3523. self.__challenge = self.__serverConfig.get('global', 'challenge')
  3524. else:
  3525. self.__challenge = 'A'*8
  3526. if self.__serverConfig.has_option("global", "jtr_dump_path"):
  3527. self.__jtr_dump_path = self.__serverConfig.get("global", "jtr_dump_path")
  3528. if self.__serverConfig.has_option("global", "SMB2Support"):
  3529. self.__SMB2Support = self.__serverConfig.getboolean("global","SMB2Support")
  3530. else:
  3531. self.__SMB2Support = False
  3532. if self.__logFile != 'None':
  3533. logging.basicConfig(filename = self.__logFile,
  3534. level = logging.DEBUG,
  3535. format="%(asctime)s: %(levelname)s: %(message)s",
  3536. datefmt = '%m/%d/%Y %I:%M:%S %p')
  3537. self.__log = LOG
  3538. # Process the credentials
  3539. credentials_fname = self.__serverConfig.get('global','credentials_file')
  3540. if credentials_fname is not "":
  3541. cred = open(credentials_fname)
  3542. line = cred.readline()
  3543. while line:
  3544. name, domain, lmhash, nthash = line.split(':')
  3545. self.__credentials[name] = (domain, lmhash, nthash.strip('\r\n'))
  3546. line = cred.readline()
  3547. cred.close()
  3548. self.log('Config file parsed')
  3549. # For windows platforms, opening a directory is not an option, so we set a void FD
  3550. VOID_FILE_DESCRIPTOR = -1
  3551. PIPE_FILE_DESCRIPTOR = -2