Без опису

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619
  1. <?php
  2. /**
  3. * Pure-PHP implementation of SSHv2.
  4. *
  5. * PHP version 5
  6. *
  7. * Here are some examples of how to use this library:
  8. * <code>
  9. * <?php
  10. * include 'vendor/autoload.php';
  11. *
  12. * $ssh = new \phpseclib\Net\SSH2('www.domain.tld');
  13. * if (!$ssh->login('username', 'password')) {
  14. * exit('Login Failed');
  15. * }
  16. *
  17. * echo $ssh->exec('pwd');
  18. * echo $ssh->exec('ls -la');
  19. * ?>
  20. * </code>
  21. *
  22. * <code>
  23. * <?php
  24. * include 'vendor/autoload.php';
  25. *
  26. * $key = new \phpseclib\Crypt\RSA();
  27. * //$key->setPassword('whatever');
  28. * $key->loadKey(file_get_contents('privatekey'));
  29. *
  30. * $ssh = new \phpseclib\Net\SSH2('www.domain.tld');
  31. * if (!$ssh->login('username', $key)) {
  32. * exit('Login Failed');
  33. * }
  34. *
  35. * echo $ssh->read('username@username:~$');
  36. * $ssh->write("ls -la\n");
  37. * echo $ssh->read('username@username:~$');
  38. * ?>
  39. * </code>
  40. *
  41. * @category Net
  42. * @package SSH2
  43. * @author Jim Wigginton <terrafrost@php.net>
  44. * @copyright 2007 Jim Wigginton
  45. * @license http://www.opensource.org/licenses/mit-license.html MIT License
  46. * @link http://phpseclib.sourceforge.net
  47. */
  48. namespace phpseclib\Net;
  49. use phpseclib\Crypt\Base;
  50. use phpseclib\Crypt\Blowfish;
  51. use phpseclib\Crypt\Hash;
  52. use phpseclib\Crypt\Random;
  53. use phpseclib\Crypt\RC4;
  54. use phpseclib\Crypt\Rijndael;
  55. use phpseclib\Crypt\RSA;
  56. use phpseclib\Crypt\TripleDES;
  57. use phpseclib\Crypt\Twofish;
  58. use phpseclib\Math\BigInteger; // Used to do Diffie-Hellman key exchange and DSA/RSA signature verification.
  59. use phpseclib\System\SSH\Agent;
  60. /**
  61. * Pure-PHP implementation of SSHv2.
  62. *
  63. * @package SSH2
  64. * @author Jim Wigginton <terrafrost@php.net>
  65. * @access public
  66. */
  67. class SSH2
  68. {
  69. /**#@+
  70. * Execution Bitmap Masks
  71. *
  72. * @see \phpseclib\Net\SSH2::bitmap
  73. * @access private
  74. */
  75. const MASK_CONSTRUCTOR = 0x00000001;
  76. const MASK_CONNECTED = 0x00000002;
  77. const MASK_LOGIN_REQ = 0x00000004;
  78. const MASK_LOGIN = 0x00000008;
  79. const MASK_SHELL = 0x00000010;
  80. const MASK_WINDOW_ADJUST = 0x00000020;
  81. /**#@-*/
  82. /**#@+
  83. * Channel constants
  84. *
  85. * RFC4254 refers not to client and server channels but rather to sender and recipient channels. we don't refer
  86. * to them in that way because RFC4254 toggles the meaning. the client sends a SSH_MSG_CHANNEL_OPEN message with
  87. * a sender channel and the server sends a SSH_MSG_CHANNEL_OPEN_CONFIRMATION in response, with a sender and a
  88. * recepient channel. at first glance, you might conclude that SSH_MSG_CHANNEL_OPEN_CONFIRMATION's sender channel
  89. * would be the same thing as SSH_MSG_CHANNEL_OPEN's sender channel, but it's not, per this snipet:
  90. * The 'recipient channel' is the channel number given in the original
  91. * open request, and 'sender channel' is the channel number allocated by
  92. * the other side.
  93. *
  94. * @see \phpseclib\Net\SSH2::_send_channel_packet()
  95. * @see \phpseclib\Net\SSH2::_get_channel_packet()
  96. * @access private
  97. */
  98. const CHANNEL_EXEC = 1; // PuTTy uses 0x100
  99. const CHANNEL_SHELL = 2;
  100. const CHANNEL_SUBSYSTEM = 3;
  101. const CHANNEL_AGENT_FORWARD = 4;
  102. /**#@-*/
  103. /**#@+
  104. * @access public
  105. * @see \phpseclib\Net\SSH2::getLog()
  106. */
  107. /**
  108. * Returns the message numbers
  109. */
  110. const LOG_SIMPLE = 1;
  111. /**
  112. * Returns the message content
  113. */
  114. const LOG_COMPLEX = 2;
  115. /**
  116. * Outputs the content real-time
  117. */
  118. const LOG_REALTIME = 3;
  119. /**
  120. * Dumps the content real-time to a file
  121. */
  122. const LOG_REALTIME_FILE = 4;
  123. /**
  124. * Make sure that the log never gets larger than this
  125. */
  126. const LOG_MAX_SIZE = 1048576; // 1024 * 1024
  127. /**#@-*/
  128. /**#@+
  129. * @access public
  130. * @see \phpseclib\Net\SSH2::read()
  131. */
  132. /**
  133. * Returns when a string matching $expect exactly is found
  134. */
  135. const READ_SIMPLE = 1;
  136. /**
  137. * Returns when a string matching the regular expression $expect is found
  138. */
  139. const READ_REGEX = 2;
  140. /**
  141. * Returns when a string matching the regular expression $expect is found
  142. */
  143. const READ_NEXT = 3;
  144. /**#@-*/
  145. /**
  146. * The SSH identifier
  147. *
  148. * @var string
  149. * @access private
  150. */
  151. var $identifier;
  152. /**
  153. * The Socket Object
  154. *
  155. * @var object
  156. * @access private
  157. */
  158. var $fsock;
  159. /**
  160. * Execution Bitmap
  161. *
  162. * The bits that are set represent functions that have been called already. This is used to determine
  163. * if a requisite function has been successfully executed. If not, an error should be thrown.
  164. *
  165. * @var int
  166. * @access private
  167. */
  168. var $bitmap = 0;
  169. /**
  170. * Error information
  171. *
  172. * @see self::getErrors()
  173. * @see self::getLastError()
  174. * @var string
  175. * @access private
  176. */
  177. var $errors = array();
  178. /**
  179. * Server Identifier
  180. *
  181. * @see self::getServerIdentification()
  182. * @var array|false
  183. * @access private
  184. */
  185. var $server_identifier = false;
  186. /**
  187. * Key Exchange Algorithms
  188. *
  189. * @see self::getKexAlgorithims()
  190. * @var array|false
  191. * @access private
  192. */
  193. var $kex_algorithms = false;
  194. /**
  195. * Minimum Diffie-Hellman Group Bit Size in RFC 4419 Key Exchange Methods
  196. *
  197. * @see self::_key_exchange()
  198. * @var int
  199. * @access private
  200. */
  201. var $kex_dh_group_size_min = 1536;
  202. /**
  203. * Preferred Diffie-Hellman Group Bit Size in RFC 4419 Key Exchange Methods
  204. *
  205. * @see self::_key_exchange()
  206. * @var int
  207. * @access private
  208. */
  209. var $kex_dh_group_size_preferred = 2048;
  210. /**
  211. * Maximum Diffie-Hellman Group Bit Size in RFC 4419 Key Exchange Methods
  212. *
  213. * @see self::_key_exchange()
  214. * @var int
  215. * @access private
  216. */
  217. var $kex_dh_group_size_max = 4096;
  218. /**
  219. * Server Host Key Algorithms
  220. *
  221. * @see self::getServerHostKeyAlgorithms()
  222. * @var array|false
  223. * @access private
  224. */
  225. var $server_host_key_algorithms = false;
  226. /**
  227. * Encryption Algorithms: Client to Server
  228. *
  229. * @see self::getEncryptionAlgorithmsClient2Server()
  230. * @var array|false
  231. * @access private
  232. */
  233. var $encryption_algorithms_client_to_server = false;
  234. /**
  235. * Encryption Algorithms: Server to Client
  236. *
  237. * @see self::getEncryptionAlgorithmsServer2Client()
  238. * @var array|false
  239. * @access private
  240. */
  241. var $encryption_algorithms_server_to_client = false;
  242. /**
  243. * MAC Algorithms: Client to Server
  244. *
  245. * @see self::getMACAlgorithmsClient2Server()
  246. * @var array|false
  247. * @access private
  248. */
  249. var $mac_algorithms_client_to_server = false;
  250. /**
  251. * MAC Algorithms: Server to Client
  252. *
  253. * @see self::getMACAlgorithmsServer2Client()
  254. * @var array|false
  255. * @access private
  256. */
  257. var $mac_algorithms_server_to_client = false;
  258. /**
  259. * Compression Algorithms: Client to Server
  260. *
  261. * @see self::getCompressionAlgorithmsClient2Server()
  262. * @var array|false
  263. * @access private
  264. */
  265. var $compression_algorithms_client_to_server = false;
  266. /**
  267. * Compression Algorithms: Server to Client
  268. *
  269. * @see self::getCompressionAlgorithmsServer2Client()
  270. * @var array|false
  271. * @access private
  272. */
  273. var $compression_algorithms_server_to_client = false;
  274. /**
  275. * Languages: Server to Client
  276. *
  277. * @see self::getLanguagesServer2Client()
  278. * @var array|false
  279. * @access private
  280. */
  281. var $languages_server_to_client = false;
  282. /**
  283. * Languages: Client to Server
  284. *
  285. * @see self::getLanguagesClient2Server()
  286. * @var array|false
  287. * @access private
  288. */
  289. var $languages_client_to_server = false;
  290. /**
  291. * Block Size for Server to Client Encryption
  292. *
  293. * "Note that the length of the concatenation of 'packet_length',
  294. * 'padding_length', 'payload', and 'random padding' MUST be a multiple
  295. * of the cipher block size or 8, whichever is larger. This constraint
  296. * MUST be enforced, even when using stream ciphers."
  297. *
  298. * -- http://tools.ietf.org/html/rfc4253#section-6
  299. *
  300. * @see self::__construct()
  301. * @see self::_send_binary_packet()
  302. * @var int
  303. * @access private
  304. */
  305. var $encrypt_block_size = 8;
  306. /**
  307. * Block Size for Client to Server Encryption
  308. *
  309. * @see self::__construct()
  310. * @see self::_get_binary_packet()
  311. * @var int
  312. * @access private
  313. */
  314. var $decrypt_block_size = 8;
  315. /**
  316. * Server to Client Encryption Object
  317. *
  318. * @see self::_get_binary_packet()
  319. * @var object
  320. * @access private
  321. */
  322. var $decrypt = false;
  323. /**
  324. * Client to Server Encryption Object
  325. *
  326. * @see self::_send_binary_packet()
  327. * @var object
  328. * @access private
  329. */
  330. var $encrypt = false;
  331. /**
  332. * Client to Server HMAC Object
  333. *
  334. * @see self::_send_binary_packet()
  335. * @var object
  336. * @access private
  337. */
  338. var $hmac_create = false;
  339. /**
  340. * Server to Client HMAC Object
  341. *
  342. * @see self::_get_binary_packet()
  343. * @var object
  344. * @access private
  345. */
  346. var $hmac_check = false;
  347. /**
  348. * Size of server to client HMAC
  349. *
  350. * We need to know how big the HMAC will be for the server to client direction so that we know how many bytes to read.
  351. * For the client to server side, the HMAC object will make the HMAC as long as it needs to be. All we need to do is
  352. * append it.
  353. *
  354. * @see self::_get_binary_packet()
  355. * @var int
  356. * @access private
  357. */
  358. var $hmac_size = false;
  359. /**
  360. * Server Public Host Key
  361. *
  362. * @see self::getServerPublicHostKey()
  363. * @var string
  364. * @access private
  365. */
  366. var $server_public_host_key;
  367. /**
  368. * Session identifier
  369. *
  370. * "The exchange hash H from the first key exchange is additionally
  371. * used as the session identifier, which is a unique identifier for
  372. * this connection."
  373. *
  374. * -- http://tools.ietf.org/html/rfc4253#section-7.2
  375. *
  376. * @see self::_key_exchange()
  377. * @var string
  378. * @access private
  379. */
  380. var $session_id = false;
  381. /**
  382. * Exchange hash
  383. *
  384. * The current exchange hash
  385. *
  386. * @see self::_key_exchange()
  387. * @var string
  388. * @access private
  389. */
  390. var $exchange_hash = false;
  391. /**
  392. * Message Numbers
  393. *
  394. * @see self::__construct()
  395. * @var array
  396. * @access private
  397. */
  398. var $message_numbers = array();
  399. /**
  400. * Disconnection Message 'reason codes' defined in RFC4253
  401. *
  402. * @see self::__construct()
  403. * @var array
  404. * @access private
  405. */
  406. var $disconnect_reasons = array();
  407. /**
  408. * SSH_MSG_CHANNEL_OPEN_FAILURE 'reason codes', defined in RFC4254
  409. *
  410. * @see self::__construct()
  411. * @var array
  412. * @access private
  413. */
  414. var $channel_open_failure_reasons = array();
  415. /**
  416. * Terminal Modes
  417. *
  418. * @link http://tools.ietf.org/html/rfc4254#section-8
  419. * @see self::__construct()
  420. * @var array
  421. * @access private
  422. */
  423. var $terminal_modes = array();
  424. /**
  425. * SSH_MSG_CHANNEL_EXTENDED_DATA's data_type_codes
  426. *
  427. * @link http://tools.ietf.org/html/rfc4254#section-5.2
  428. * @see self::__construct()
  429. * @var array
  430. * @access private
  431. */
  432. var $channel_extended_data_type_codes = array();
  433. /**
  434. * Send Sequence Number
  435. *
  436. * See 'Section 6.4. Data Integrity' of rfc4253 for more info.
  437. *
  438. * @see self::_send_binary_packet()
  439. * @var int
  440. * @access private
  441. */
  442. var $send_seq_no = 0;
  443. /**
  444. * Get Sequence Number
  445. *
  446. * See 'Section 6.4. Data Integrity' of rfc4253 for more info.
  447. *
  448. * @see self::_get_binary_packet()
  449. * @var int
  450. * @access private
  451. */
  452. var $get_seq_no = 0;
  453. /**
  454. * Server Channels
  455. *
  456. * Maps client channels to server channels
  457. *
  458. * @see self::_get_channel_packet()
  459. * @see self::exec()
  460. * @var array
  461. * @access private
  462. */
  463. var $server_channels = array();
  464. /**
  465. * Channel Buffers
  466. *
  467. * If a client requests a packet from one channel but receives two packets from another those packets should
  468. * be placed in a buffer
  469. *
  470. * @see self::_get_channel_packet()
  471. * @see self::exec()
  472. * @var array
  473. * @access private
  474. */
  475. var $channel_buffers = array();
  476. /**
  477. * Channel Status
  478. *
  479. * Contains the type of the last sent message
  480. *
  481. * @see self::_get_channel_packet()
  482. * @var array
  483. * @access private
  484. */
  485. var $channel_status = array();
  486. /**
  487. * Packet Size
  488. *
  489. * Maximum packet size indexed by channel
  490. *
  491. * @see self::_send_channel_packet()
  492. * @var array
  493. * @access private
  494. */
  495. var $packet_size_client_to_server = array();
  496. /**
  497. * Message Number Log
  498. *
  499. * @see self::getLog()
  500. * @var array
  501. * @access private
  502. */
  503. var $message_number_log = array();
  504. /**
  505. * Message Log
  506. *
  507. * @see self::getLog()
  508. * @var array
  509. * @access private
  510. */
  511. var $message_log = array();
  512. /**
  513. * The Window Size
  514. *
  515. * Bytes the other party can send before it must wait for the window to be adjusted (0x7FFFFFFF = 2GB)
  516. *
  517. * @var int
  518. * @see self::_send_channel_packet()
  519. * @see self::exec()
  520. * @access private
  521. */
  522. var $window_size = 0x7FFFFFFF;
  523. /**
  524. * Window size, server to client
  525. *
  526. * Window size indexed by channel
  527. *
  528. * @see self::_send_channel_packet()
  529. * @var array
  530. * @access private
  531. */
  532. var $window_size_server_to_client = array();
  533. /**
  534. * Window size, client to server
  535. *
  536. * Window size indexed by channel
  537. *
  538. * @see self::_get_channel_packet()
  539. * @var array
  540. * @access private
  541. */
  542. var $window_size_client_to_server = array();
  543. /**
  544. * Server signature
  545. *
  546. * Verified against $this->session_id
  547. *
  548. * @see self::getServerPublicHostKey()
  549. * @var string
  550. * @access private
  551. */
  552. var $signature = '';
  553. /**
  554. * Server signature format
  555. *
  556. * ssh-rsa or ssh-dss.
  557. *
  558. * @see self::getServerPublicHostKey()
  559. * @var string
  560. * @access private
  561. */
  562. var $signature_format = '';
  563. /**
  564. * Interactive Buffer
  565. *
  566. * @see self::read()
  567. * @var array
  568. * @access private
  569. */
  570. var $interactiveBuffer = '';
  571. /**
  572. * Current log size
  573. *
  574. * Should never exceed self::LOG_MAX_SIZE
  575. *
  576. * @see self::_send_binary_packet()
  577. * @see self::_get_binary_packet()
  578. * @var int
  579. * @access private
  580. */
  581. var $log_size;
  582. /**
  583. * Timeout
  584. *
  585. * @see self::setTimeout()
  586. * @access private
  587. */
  588. var $timeout;
  589. /**
  590. * Current Timeout
  591. *
  592. * @see self::_get_channel_packet()
  593. * @access private
  594. */
  595. var $curTimeout;
  596. /**
  597. * Real-time log file pointer
  598. *
  599. * @see self::_append_log()
  600. * @var resource
  601. * @access private
  602. */
  603. var $realtime_log_file;
  604. /**
  605. * Real-time log file size
  606. *
  607. * @see self::_append_log()
  608. * @var int
  609. * @access private
  610. */
  611. var $realtime_log_size;
  612. /**
  613. * Has the signature been validated?
  614. *
  615. * @see self::getServerPublicHostKey()
  616. * @var bool
  617. * @access private
  618. */
  619. var $signature_validated = false;
  620. /**
  621. * Real-time log file wrap boolean
  622. *
  623. * @see self::_append_log()
  624. * @access private
  625. */
  626. var $realtime_log_wrap;
  627. /**
  628. * Flag to suppress stderr from output
  629. *
  630. * @see self::enableQuietMode()
  631. * @access private
  632. */
  633. var $quiet_mode = false;
  634. /**
  635. * Time of first network activity
  636. *
  637. * @var int
  638. * @access private
  639. */
  640. var $last_packet;
  641. /**
  642. * Exit status returned from ssh if any
  643. *
  644. * @var int
  645. * @access private
  646. */
  647. var $exit_status;
  648. /**
  649. * Flag to request a PTY when using exec()
  650. *
  651. * @var bool
  652. * @see self::enablePTY()
  653. * @access private
  654. */
  655. var $request_pty = false;
  656. /**
  657. * Flag set while exec() is running when using enablePTY()
  658. *
  659. * @var bool
  660. * @access private
  661. */
  662. var $in_request_pty_exec = false;
  663. /**
  664. * Flag set after startSubsystem() is called
  665. *
  666. * @var bool
  667. * @access private
  668. */
  669. var $in_subsystem;
  670. /**
  671. * Contents of stdError
  672. *
  673. * @var string
  674. * @access private
  675. */
  676. var $stdErrorLog;
  677. /**
  678. * The Last Interactive Response
  679. *
  680. * @see self::_keyboard_interactive_process()
  681. * @var string
  682. * @access private
  683. */
  684. var $last_interactive_response = '';
  685. /**
  686. * Keyboard Interactive Request / Responses
  687. *
  688. * @see self::_keyboard_interactive_process()
  689. * @var array
  690. * @access private
  691. */
  692. var $keyboard_requests_responses = array();
  693. /**
  694. * Banner Message
  695. *
  696. * Quoting from the RFC, "in some jurisdictions, sending a warning message before
  697. * authentication may be relevant for getting legal protection."
  698. *
  699. * @see self::_filter()
  700. * @see self::getBannerMessage()
  701. * @var string
  702. * @access private
  703. */
  704. var $banner_message = '';
  705. /**
  706. * Did read() timeout or return normally?
  707. *
  708. * @see self::isTimeout()
  709. * @var bool
  710. * @access private
  711. */
  712. var $is_timeout = false;
  713. /**
  714. * Log Boundary
  715. *
  716. * @see self::_format_log()
  717. * @var string
  718. * @access private
  719. */
  720. var $log_boundary = ':';
  721. /**
  722. * Log Long Width
  723. *
  724. * @see self::_format_log()
  725. * @var int
  726. * @access private
  727. */
  728. var $log_long_width = 65;
  729. /**
  730. * Log Short Width
  731. *
  732. * @see self::_format_log()
  733. * @var int
  734. * @access private
  735. */
  736. var $log_short_width = 16;
  737. /**
  738. * Hostname
  739. *
  740. * @see self::__construct()
  741. * @see self::_connect()
  742. * @var string
  743. * @access private
  744. */
  745. var $host;
  746. /**
  747. * Port Number
  748. *
  749. * @see self::__construct()
  750. * @see self::_connect()
  751. * @var int
  752. * @access private
  753. */
  754. var $port;
  755. /**
  756. * Number of columns for terminal window size
  757. *
  758. * @see self::getWindowColumns()
  759. * @see self::setWindowColumns()
  760. * @see self::setWindowSize()
  761. * @var int
  762. * @access private
  763. */
  764. var $windowColumns = 80;
  765. /**
  766. * Number of columns for terminal window size
  767. *
  768. * @see self::getWindowRows()
  769. * @see self::setWindowRows()
  770. * @see self::setWindowSize()
  771. * @var int
  772. * @access private
  773. */
  774. var $windowRows = 24;
  775. /**
  776. * Crypto Engine
  777. *
  778. * @see self::setCryptoEngine()
  779. * @see self::_key_exchange()
  780. * @var int
  781. * @access private
  782. */
  783. var $crypto_engine = false;
  784. /**
  785. * A System_SSH_Agent for use in the SSH2 Agent Forwarding scenario
  786. *
  787. * @var System_SSH_Agent
  788. * @access private
  789. */
  790. var $agent;
  791. /**
  792. * Send the identification string first?
  793. *
  794. * @var bool
  795. * @access private
  796. */
  797. var $send_id_string_first = true;
  798. /**
  799. * Send the key exchange initiation packet first?
  800. *
  801. * @var bool
  802. * @access private
  803. */
  804. var $send_kex_first = true;
  805. /**
  806. * Some versions of OpenSSH incorrectly calculate the key size
  807. *
  808. * @var bool
  809. * @access private
  810. */
  811. var $bad_key_size_fix = false;
  812. /**
  813. * The selected decryption algorithm
  814. *
  815. * @var string
  816. * @access private
  817. */
  818. var $decrypt_algorithm = '';
  819. /**
  820. * Should we try to re-connect to re-establish keys?
  821. *
  822. * @var bool
  823. * @access private
  824. */
  825. var $retry_connect = false;
  826. /**
  827. * Binary Packet Buffer
  828. *
  829. * @var string|false
  830. * @access private
  831. */
  832. var $binary_packet_buffer = false;
  833. /**
  834. * Default Constructor.
  835. *
  836. * $host can either be a string, representing the host, or a stream resource.
  837. *
  838. * @param mixed $host
  839. * @param int $port
  840. * @param int $timeout
  841. * @see self::login()
  842. * @return \phpseclib\Net\SSH2
  843. * @access public
  844. */
  845. function __construct($host, $port = 22, $timeout = 10)
  846. {
  847. $this->message_numbers = array(
  848. 1 => 'NET_SSH2_MSG_DISCONNECT',
  849. 2 => 'NET_SSH2_MSG_IGNORE',
  850. 3 => 'NET_SSH2_MSG_UNIMPLEMENTED',
  851. 4 => 'NET_SSH2_MSG_DEBUG',
  852. 5 => 'NET_SSH2_MSG_SERVICE_REQUEST',
  853. 6 => 'NET_SSH2_MSG_SERVICE_ACCEPT',
  854. 20 => 'NET_SSH2_MSG_KEXINIT',
  855. 21 => 'NET_SSH2_MSG_NEWKEYS',
  856. 30 => 'NET_SSH2_MSG_KEXDH_INIT',
  857. 31 => 'NET_SSH2_MSG_KEXDH_REPLY',
  858. 50 => 'NET_SSH2_MSG_USERAUTH_REQUEST',
  859. 51 => 'NET_SSH2_MSG_USERAUTH_FAILURE',
  860. 52 => 'NET_SSH2_MSG_USERAUTH_SUCCESS',
  861. 53 => 'NET_SSH2_MSG_USERAUTH_BANNER',
  862. 80 => 'NET_SSH2_MSG_GLOBAL_REQUEST',
  863. 81 => 'NET_SSH2_MSG_REQUEST_SUCCESS',
  864. 82 => 'NET_SSH2_MSG_REQUEST_FAILURE',
  865. 90 => 'NET_SSH2_MSG_CHANNEL_OPEN',
  866. 91 => 'NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION',
  867. 92 => 'NET_SSH2_MSG_CHANNEL_OPEN_FAILURE',
  868. 93 => 'NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST',
  869. 94 => 'NET_SSH2_MSG_CHANNEL_DATA',
  870. 95 => 'NET_SSH2_MSG_CHANNEL_EXTENDED_DATA',
  871. 96 => 'NET_SSH2_MSG_CHANNEL_EOF',
  872. 97 => 'NET_SSH2_MSG_CHANNEL_CLOSE',
  873. 98 => 'NET_SSH2_MSG_CHANNEL_REQUEST',
  874. 99 => 'NET_SSH2_MSG_CHANNEL_SUCCESS',
  875. 100 => 'NET_SSH2_MSG_CHANNEL_FAILURE'
  876. );
  877. $this->disconnect_reasons = array(
  878. 1 => 'NET_SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT',
  879. 2 => 'NET_SSH2_DISCONNECT_PROTOCOL_ERROR',
  880. 3 => 'NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED',
  881. 4 => 'NET_SSH2_DISCONNECT_RESERVED',
  882. 5 => 'NET_SSH2_DISCONNECT_MAC_ERROR',
  883. 6 => 'NET_SSH2_DISCONNECT_COMPRESSION_ERROR',
  884. 7 => 'NET_SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE',
  885. 8 => 'NET_SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED',
  886. 9 => 'NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE',
  887. 10 => 'NET_SSH2_DISCONNECT_CONNECTION_LOST',
  888. 11 => 'NET_SSH2_DISCONNECT_BY_APPLICATION',
  889. 12 => 'NET_SSH2_DISCONNECT_TOO_MANY_CONNECTIONS',
  890. 13 => 'NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER',
  891. 14 => 'NET_SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE',
  892. 15 => 'NET_SSH2_DISCONNECT_ILLEGAL_USER_NAME'
  893. );
  894. $this->channel_open_failure_reasons = array(
  895. 1 => 'NET_SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED'
  896. );
  897. $this->terminal_modes = array(
  898. 0 => 'NET_SSH2_TTY_OP_END'
  899. );
  900. $this->channel_extended_data_type_codes = array(
  901. 1 => 'NET_SSH2_EXTENDED_DATA_STDERR'
  902. );
  903. $this->_define_array(
  904. $this->message_numbers,
  905. $this->disconnect_reasons,
  906. $this->channel_open_failure_reasons,
  907. $this->terminal_modes,
  908. $this->channel_extended_data_type_codes,
  909. array(60 => 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ'),
  910. array(60 => 'NET_SSH2_MSG_USERAUTH_PK_OK'),
  911. array(60 => 'NET_SSH2_MSG_USERAUTH_INFO_REQUEST',
  912. 61 => 'NET_SSH2_MSG_USERAUTH_INFO_RESPONSE'),
  913. // RFC 4419 - diffie-hellman-group-exchange-sha{1,256}
  914. array(30 => 'NET_SSH2_MSG_KEXDH_GEX_REQUEST_OLD',
  915. 31 => 'NET_SSH2_MSG_KEXDH_GEX_GROUP',
  916. 32 => 'NET_SSH2_MSG_KEXDH_GEX_INIT',
  917. 33 => 'NET_SSH2_MSG_KEXDH_GEX_REPLY',
  918. 34 => 'NET_SSH2_MSG_KEXDH_GEX_REQUEST'),
  919. // RFC 5656 - Elliptic Curves (for curve25519-sha256@libssh.org)
  920. array(30 => 'NET_SSH2_MSG_KEX_ECDH_INIT',
  921. 31 => 'NET_SSH2_MSG_KEX_ECDH_REPLY')
  922. );
  923. if (is_resource($host)) {
  924. $this->fsock = $host;
  925. return;
  926. }
  927. if (is_string($host)) {
  928. $this->host = $host;
  929. $this->port = $port;
  930. $this->timeout = $timeout;
  931. }
  932. }
  933. /**
  934. * Set Crypto Engine Mode
  935. *
  936. * Possible $engine values:
  937. * CRYPT_MODE_INTERNAL, CRYPT_MODE_MCRYPT
  938. *
  939. * @param int $engine
  940. * @access public
  941. */
  942. function setCryptoEngine($engine)
  943. {
  944. $this->crypto_engine = $engine;
  945. }
  946. /**
  947. * Send Identification String First
  948. *
  949. * https://tools.ietf.org/html/rfc4253#section-4.2 says "when the connection has been established,
  950. * both sides MUST send an identification string". It does not say which side sends it first. In
  951. * theory it shouldn't matter but it is a fact of life that some SSH servers are simply buggy
  952. *
  953. * @access public
  954. */
  955. function sendIdentificationStringFirst()
  956. {
  957. $this->send_id_string_first = true;
  958. }
  959. /**
  960. * Send Identification String Last
  961. *
  962. * https://tools.ietf.org/html/rfc4253#section-4.2 says "when the connection has been established,
  963. * both sides MUST send an identification string". It does not say which side sends it first. In
  964. * theory it shouldn't matter but it is a fact of life that some SSH servers are simply buggy
  965. *
  966. * @access public
  967. */
  968. function sendIdentificationStringLast()
  969. {
  970. $this->send_id_string_first = false;
  971. }
  972. /**
  973. * Send SSH_MSG_KEXINIT First
  974. *
  975. * https://tools.ietf.org/html/rfc4253#section-7.1 says "key exchange begins by each sending
  976. * sending the [SSH_MSG_KEXINIT] packet". It does not say which side sends it first. In theory
  977. * it shouldn't matter but it is a fact of life that some SSH servers are simply buggy
  978. *
  979. * @access public
  980. */
  981. function sendKEXINITFirst()
  982. {
  983. $this->send_kex_first = true;
  984. }
  985. /**
  986. * Send SSH_MSG_KEXINIT Last
  987. *
  988. * https://tools.ietf.org/html/rfc4253#section-7.1 says "key exchange begins by each sending
  989. * sending the [SSH_MSG_KEXINIT] packet". It does not say which side sends it first. In theory
  990. * it shouldn't matter but it is a fact of life that some SSH servers are simply buggy
  991. *
  992. * @access public
  993. */
  994. function sendKEXINITLast()
  995. {
  996. $this->send_kex_first = false;
  997. }
  998. /**
  999. * Connect to an SSHv2 server
  1000. *
  1001. * @return bool
  1002. * @access private
  1003. */
  1004. function _connect()
  1005. {
  1006. if ($this->bitmap & self::MASK_CONSTRUCTOR) {
  1007. return false;
  1008. }
  1009. $this->bitmap |= self::MASK_CONSTRUCTOR;
  1010. $this->curTimeout = $this->timeout;
  1011. $this->last_packet = microtime(true);
  1012. if (!is_resource($this->fsock)) {
  1013. $start = microtime(true);
  1014. // with stream_select a timeout of 0 means that no timeout takes place;
  1015. // with fsockopen a timeout of 0 means that you instantly timeout
  1016. // to resolve this incompatibility a timeout of 100,000 will be used for fsockopen if timeout is 0
  1017. $this->fsock = @fsockopen($this->host, $this->port, $errno, $errstr, $this->curTimeout == 0 ? 100000 : $this->curTimeout);
  1018. if (!$this->fsock) {
  1019. $host = $this->host . ':' . $this->port;
  1020. user_error(rtrim("Cannot connect to $host. Error $errno. $errstr"));
  1021. return false;
  1022. }
  1023. $elapsed = microtime(true) - $start;
  1024. $this->curTimeout-= $elapsed;
  1025. if ($this->curTimeout <= 0) {
  1026. $this->is_timeout = true;
  1027. return false;
  1028. }
  1029. }
  1030. $this->identifier = $this->_generate_identifier();
  1031. if ($this->send_id_string_first) {
  1032. fputs($this->fsock, $this->identifier . "\r\n");
  1033. }
  1034. /* According to the SSH2 specs,
  1035. "The server MAY send other lines of data before sending the version
  1036. string. Each line SHOULD be terminated by a Carriage Return and Line
  1037. Feed. Such lines MUST NOT begin with "SSH-", and SHOULD be encoded
  1038. in ISO-10646 UTF-8 [RFC3629] (language is not specified). Clients
  1039. MUST be able to process such lines." */
  1040. $data = '';
  1041. while (!feof($this->fsock) && !preg_match('#(.*)^(SSH-(\d\.\d+).*)#ms', $data, $matches)) {
  1042. $line = '';
  1043. while (true) {
  1044. if ($this->curTimeout) {
  1045. if ($this->curTimeout < 0) {
  1046. $this->is_timeout = true;
  1047. return false;
  1048. }
  1049. $read = array($this->fsock);
  1050. $write = $except = null;
  1051. $start = microtime(true);
  1052. $sec = floor($this->curTimeout);
  1053. $usec = 1000000 * ($this->curTimeout - $sec);
  1054. // on windows this returns a "Warning: Invalid CRT parameters detected" error
  1055. // the !count() is done as a workaround for <https://bugs.php.net/42682>
  1056. if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) {
  1057. $this->is_timeout = true;
  1058. return false;
  1059. }
  1060. $elapsed = microtime(true) - $start;
  1061. $this->curTimeout-= $elapsed;
  1062. }
  1063. $temp = stream_get_line($this->fsock, 255, "\n");
  1064. if (strlen($temp) == 255) {
  1065. continue;
  1066. }
  1067. $line.= "$temp\n";
  1068. // quoting RFC4253, "Implementers who wish to maintain
  1069. // compatibility with older, undocumented versions of this protocol may
  1070. // want to process the identification string without expecting the
  1071. // presence of the carriage return character for reasons described in
  1072. // Section 5 of this document."
  1073. //if (substr($line, -2) == "\r\n") {
  1074. // break;
  1075. //}
  1076. break;
  1077. }
  1078. $data.= $line;
  1079. }
  1080. if (feof($this->fsock)) {
  1081. user_error('Connection closed by server');
  1082. return false;
  1083. }
  1084. $extra = $matches[1];
  1085. if (defined('NET_SSH2_LOGGING')) {
  1086. $this->_append_log('<-', $matches[0]);
  1087. $this->_append_log('->', $this->identifier . "\r\n");
  1088. }
  1089. $this->server_identifier = trim($temp, "\r\n");
  1090. if (strlen($extra)) {
  1091. $this->errors[] = utf8_decode($data);
  1092. }
  1093. if (version_compare($matches[3], '1.99', '<')) {
  1094. user_error("Cannot connect to SSH $matches[3] servers");
  1095. return false;
  1096. }
  1097. if (!$this->send_id_string_first) {
  1098. fputs($this->fsock, $this->identifier . "\r\n");
  1099. }
  1100. if (!$this->send_kex_first) {
  1101. $response = $this->_get_binary_packet();
  1102. if ($response === false) {
  1103. user_error('Connection closed by server');
  1104. return false;
  1105. }
  1106. if (!strlen($response) || ord($response[0]) != NET_SSH2_MSG_KEXINIT) {
  1107. user_error('Expected SSH_MSG_KEXINIT');
  1108. return false;
  1109. }
  1110. if (!$this->_key_exchange($response)) {
  1111. return false;
  1112. }
  1113. }
  1114. if ($this->send_kex_first && !$this->_key_exchange()) {
  1115. return false;
  1116. }
  1117. $this->bitmap|= self::MASK_CONNECTED;
  1118. return true;
  1119. }
  1120. /**
  1121. * Generates the SSH identifier
  1122. *
  1123. * You should overwrite this method in your own class if you want to use another identifier
  1124. *
  1125. * @access protected
  1126. * @return string
  1127. */
  1128. function _generate_identifier()
  1129. {
  1130. $identifier = 'SSH-2.0-phpseclib_2.0';
  1131. $ext = array();
  1132. if (function_exists('\\Sodium\\library_version_major')) {
  1133. $ext[] = 'libsodium';
  1134. }
  1135. if (extension_loaded('openssl')) {
  1136. $ext[] = 'openssl';
  1137. } elseif (extension_loaded('mcrypt')) {
  1138. $ext[] = 'mcrypt';
  1139. }
  1140. if (extension_loaded('gmp')) {
  1141. $ext[] = 'gmp';
  1142. } elseif (extension_loaded('bcmath')) {
  1143. $ext[] = 'bcmath';
  1144. }
  1145. if (!empty($ext)) {
  1146. $identifier .= ' (' . implode(', ', $ext) . ')';
  1147. }
  1148. return $identifier;
  1149. }
  1150. /**
  1151. * Key Exchange
  1152. *
  1153. * @param string $kexinit_payload_server optional
  1154. * @access private
  1155. */
  1156. function _key_exchange($kexinit_payload_server = false)
  1157. {
  1158. $kex_algorithms = array(
  1159. // Elliptic Curve Diffie-Hellman Key Agreement (ECDH) using
  1160. // Curve25519. See doc/curve25519-sha256@libssh.org.txt in the
  1161. // libssh repository for more information.
  1162. 'curve25519-sha256@libssh.org',
  1163. // Diffie-Hellman Key Agreement (DH) using integer modulo prime
  1164. // groups.
  1165. 'diffie-hellman-group1-sha1', // REQUIRED
  1166. 'diffie-hellman-group14-sha1', // REQUIRED
  1167. 'diffie-hellman-group-exchange-sha1', // RFC 4419
  1168. 'diffie-hellman-group-exchange-sha256', // RFC 4419
  1169. );
  1170. if (!function_exists('\\Sodium\\library_version_major')) {
  1171. $kex_algorithms = array_diff(
  1172. $kex_algorithms,
  1173. array('curve25519-sha256@libssh.org')
  1174. );
  1175. }
  1176. $server_host_key_algorithms = array(
  1177. 'ssh-rsa', // RECOMMENDED sign Raw RSA Key
  1178. 'ssh-dss' // REQUIRED sign Raw DSS Key
  1179. );
  1180. $encryption_algorithms = array(
  1181. // from <http://tools.ietf.org/html/rfc4345#section-4>:
  1182. 'arcfour256',
  1183. 'arcfour128',
  1184. //'arcfour', // OPTIONAL the ARCFOUR stream cipher with a 128-bit key
  1185. // CTR modes from <http://tools.ietf.org/html/rfc4344#section-4>:
  1186. 'aes128-ctr', // RECOMMENDED AES (Rijndael) in SDCTR mode, with 128-bit key
  1187. 'aes192-ctr', // RECOMMENDED AES with 192-bit key
  1188. 'aes256-ctr', // RECOMMENDED AES with 256-bit key
  1189. 'twofish128-ctr', // OPTIONAL Twofish in SDCTR mode, with 128-bit key
  1190. 'twofish192-ctr', // OPTIONAL Twofish with 192-bit key
  1191. 'twofish256-ctr', // OPTIONAL Twofish with 256-bit key
  1192. 'aes128-cbc', // RECOMMENDED AES with a 128-bit key
  1193. 'aes192-cbc', // OPTIONAL AES with a 192-bit key
  1194. 'aes256-cbc', // OPTIONAL AES in CBC mode, with a 256-bit key
  1195. 'twofish128-cbc', // OPTIONAL Twofish with a 128-bit key
  1196. 'twofish192-cbc', // OPTIONAL Twofish with a 192-bit key
  1197. 'twofish256-cbc',
  1198. 'twofish-cbc', // OPTIONAL alias for "twofish256-cbc"
  1199. // (this is being retained for historical reasons)
  1200. 'blowfish-ctr', // OPTIONAL Blowfish in SDCTR mode
  1201. 'blowfish-cbc', // OPTIONAL Blowfish in CBC mode
  1202. '3des-ctr', // RECOMMENDED Three-key 3DES in SDCTR mode
  1203. '3des-cbc', // REQUIRED three-key 3DES in CBC mode
  1204. //'none' // OPTIONAL no encryption; NOT RECOMMENDED
  1205. );
  1206. if (extension_loaded('openssl') && !extension_loaded('mcrypt')) {
  1207. // OpenSSL does not support arcfour256 in any capacity and arcfour128 / arcfour support is limited to
  1208. // instances that do not use continuous buffers
  1209. $encryption_algorithms = array_diff(
  1210. $encryption_algorithms,
  1211. array('arcfour256', 'arcfour128', 'arcfour')
  1212. );
  1213. }
  1214. if (class_exists('\phpseclib\Crypt\RC4') === false) {
  1215. $encryption_algorithms = array_diff(
  1216. $encryption_algorithms,
  1217. array('arcfour256', 'arcfour128', 'arcfour')
  1218. );
  1219. }
  1220. if (class_exists('\phpseclib\Crypt\Rijndael') === false) {
  1221. $encryption_algorithms = array_diff(
  1222. $encryption_algorithms,
  1223. array('aes128-ctr', 'aes192-ctr', 'aes256-ctr', 'aes128-cbc', 'aes192-cbc', 'aes256-cbc')
  1224. );
  1225. }
  1226. if (class_exists('\phpseclib\Crypt\Twofish') === false) {
  1227. $encryption_algorithms = array_diff(
  1228. $encryption_algorithms,
  1229. array('twofish128-ctr', 'twofish192-ctr', 'twofish256-ctr', 'twofish128-cbc', 'twofish192-cbc', 'twofish256-cbc', 'twofish-cbc')
  1230. );
  1231. }
  1232. if (class_exists('\phpseclib\Crypt\Blowfish') === false) {
  1233. $encryption_algorithms = array_diff(
  1234. $encryption_algorithms,
  1235. array('blowfish-ctr', 'blowfish-cbc')
  1236. );
  1237. }
  1238. if (class_exists('\phpseclib\Crypt\TripleDES') === false) {
  1239. $encryption_algorithms = array_diff(
  1240. $encryption_algorithms,
  1241. array('3des-ctr', '3des-cbc')
  1242. );
  1243. }
  1244. $encryption_algorithms = array_values($encryption_algorithms);
  1245. $mac_algorithms = array(
  1246. // from <http://www.ietf.org/rfc/rfc6668.txt>:
  1247. 'hmac-sha2-256',// RECOMMENDED HMAC-SHA256 (digest length = key length = 32)
  1248. 'hmac-sha1-96', // RECOMMENDED first 96 bits of HMAC-SHA1 (digest length = 12, key length = 20)
  1249. 'hmac-sha1', // REQUIRED HMAC-SHA1 (digest length = key length = 20)
  1250. 'hmac-md5-96', // OPTIONAL first 96 bits of HMAC-MD5 (digest length = 12, key length = 16)
  1251. 'hmac-md5', // OPTIONAL HMAC-MD5 (digest length = key length = 16)
  1252. //'none' // OPTIONAL no MAC; NOT RECOMMENDED
  1253. );
  1254. $compression_algorithms = array(
  1255. 'none' // REQUIRED no compression
  1256. //'zlib' // OPTIONAL ZLIB (LZ77) compression
  1257. );
  1258. // some SSH servers have buggy implementations of some of the above algorithms
  1259. switch (true) {
  1260. case $this->server_identifier == 'SSH-2.0-SSHD':
  1261. case substr($this->server_identifier, 0, 13) == 'SSH-2.0-DLINK':
  1262. $mac_algorithms = array_values(array_diff(
  1263. $mac_algorithms,
  1264. array('hmac-sha1-96', 'hmac-md5-96')
  1265. ));
  1266. }
  1267. $str_kex_algorithms = implode(',', $kex_algorithms);
  1268. $str_server_host_key_algorithms = implode(',', $server_host_key_algorithms);
  1269. $encryption_algorithms_server_to_client = $encryption_algorithms_client_to_server = implode(',', $encryption_algorithms);
  1270. $mac_algorithms_server_to_client = $mac_algorithms_client_to_server = implode(',', $mac_algorithms);
  1271. $compression_algorithms_server_to_client = $compression_algorithms_client_to_server = implode(',', $compression_algorithms);
  1272. $client_cookie = Random::string(16);
  1273. $kexinit_payload_client = pack(
  1274. 'Ca*Na*Na*Na*Na*Na*Na*Na*Na*Na*Na*CN',
  1275. NET_SSH2_MSG_KEXINIT,
  1276. $client_cookie,
  1277. strlen($str_kex_algorithms),
  1278. $str_kex_algorithms,
  1279. strlen($str_server_host_key_algorithms),
  1280. $str_server_host_key_algorithms,
  1281. strlen($encryption_algorithms_client_to_server),
  1282. $encryption_algorithms_client_to_server,
  1283. strlen($encryption_algorithms_server_to_client),
  1284. $encryption_algorithms_server_to_client,
  1285. strlen($mac_algorithms_client_to_server),
  1286. $mac_algorithms_client_to_server,
  1287. strlen($mac_algorithms_server_to_client),
  1288. $mac_algorithms_server_to_client,
  1289. strlen($compression_algorithms_client_to_server),
  1290. $compression_algorithms_client_to_server,
  1291. strlen($compression_algorithms_server_to_client),
  1292. $compression_algorithms_server_to_client,
  1293. 0,
  1294. '',
  1295. 0,
  1296. '',
  1297. 0,
  1298. 0
  1299. );
  1300. if ($this->send_kex_first) {
  1301. if (!$this->_send_binary_packet($kexinit_payload_client)) {
  1302. return false;
  1303. }
  1304. $kexinit_payload_server = $this->_get_binary_packet();
  1305. if ($kexinit_payload_server === false) {
  1306. user_error('Connection closed by server');
  1307. return false;
  1308. }
  1309. if (!strlen($kexinit_payload_server) || ord($kexinit_payload_server[0]) != NET_SSH2_MSG_KEXINIT) {
  1310. user_error('Expected SSH_MSG_KEXINIT');
  1311. return false;
  1312. }
  1313. }
  1314. $response = $kexinit_payload_server;
  1315. $this->_string_shift($response, 1); // skip past the message number (it should be SSH_MSG_KEXINIT)
  1316. $server_cookie = $this->_string_shift($response, 16);
  1317. if (strlen($response) < 4) {
  1318. return false;
  1319. }
  1320. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  1321. $this->kex_algorithms = explode(',', $this->_string_shift($response, $temp['length']));
  1322. if (strlen($response) < 4) {
  1323. return false;
  1324. }
  1325. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  1326. $this->server_host_key_algorithms = explode(',', $this->_string_shift($response, $temp['length']));
  1327. if (strlen($response) < 4) {
  1328. return false;
  1329. }
  1330. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  1331. $this->encryption_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
  1332. if (strlen($response) < 4) {
  1333. return false;
  1334. }
  1335. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  1336. $this->encryption_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
  1337. if (strlen($response) < 4) {
  1338. return false;
  1339. }
  1340. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  1341. $this->mac_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
  1342. if (strlen($response) < 4) {
  1343. return false;
  1344. }
  1345. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  1346. $this->mac_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
  1347. if (strlen($response) < 4) {
  1348. return false;
  1349. }
  1350. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  1351. $this->compression_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
  1352. if (strlen($response) < 4) {
  1353. return false;
  1354. }
  1355. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  1356. $this->compression_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
  1357. if (strlen($response) < 4) {
  1358. return false;
  1359. }
  1360. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  1361. $this->languages_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
  1362. if (strlen($response) < 4) {
  1363. return false;
  1364. }
  1365. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  1366. $this->languages_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
  1367. if (!strlen($response)) {
  1368. return false;
  1369. }
  1370. extract(unpack('Cfirst_kex_packet_follows', $this->_string_shift($response, 1)));
  1371. $first_kex_packet_follows = $first_kex_packet_follows != 0;
  1372. if (!$this->send_kex_first && !$this->_send_binary_packet($kexinit_payload_client)) {
  1373. return false;
  1374. }
  1375. // we need to decide upon the symmetric encryption algorithms before we do the diffie-hellman key exchange
  1376. // we don't initialize any crypto-objects, yet - we do that, later. for now, we need the lengths to make the
  1377. // diffie-hellman key exchange as fast as possible
  1378. $decrypt = $this->_array_intersect_first($encryption_algorithms, $this->encryption_algorithms_server_to_client);
  1379. $decryptKeyLength = $this->_encryption_algorithm_to_key_size($decrypt);
  1380. if ($decryptKeyLength === null) {
  1381. user_error('No compatible server to client encryption algorithms found');
  1382. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  1383. }
  1384. $encrypt = $this->_array_intersect_first($encryption_algorithms, $this->encryption_algorithms_client_to_server);
  1385. $encryptKeyLength = $this->_encryption_algorithm_to_key_size($encrypt);
  1386. if ($encryptKeyLength === null) {
  1387. user_error('No compatible client to server encryption algorithms found');
  1388. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  1389. }
  1390. // through diffie-hellman key exchange a symmetric key is obtained
  1391. $kex_algorithm = $this->_array_intersect_first($kex_algorithms, $this->kex_algorithms);
  1392. if ($kex_algorithm === false) {
  1393. user_error('No compatible key exchange algorithms found');
  1394. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  1395. }
  1396. // Only relevant in diffie-hellman-group-exchange-sha{1,256}, otherwise empty.
  1397. $exchange_hash_rfc4419 = '';
  1398. if ($kex_algorithm === 'curve25519-sha256@libssh.org') {
  1399. $x = Random::string(32);
  1400. $eBytes = \Sodium\crypto_box_publickey_from_secretkey($x);
  1401. $clientKexInitMessage = NET_SSH2_MSG_KEX_ECDH_INIT;
  1402. $serverKexReplyMessage = NET_SSH2_MSG_KEX_ECDH_REPLY;
  1403. $kexHash = new Hash('sha256');
  1404. } else {
  1405. if (strpos($kex_algorithm, 'diffie-hellman-group-exchange') === 0) {
  1406. $dh_group_sizes_packed = pack(
  1407. 'NNN',
  1408. $this->kex_dh_group_size_min,
  1409. $this->kex_dh_group_size_preferred,
  1410. $this->kex_dh_group_size_max
  1411. );
  1412. $packet = pack(
  1413. 'Ca*',
  1414. NET_SSH2_MSG_KEXDH_GEX_REQUEST,
  1415. $dh_group_sizes_packed
  1416. );
  1417. if (!$this->_send_binary_packet($packet)) {
  1418. return false;
  1419. }
  1420. $response = $this->_get_binary_packet();
  1421. if ($response === false) {
  1422. user_error('Connection closed by server');
  1423. return false;
  1424. }
  1425. extract(unpack('Ctype', $this->_string_shift($response, 1)));
  1426. if ($type != NET_SSH2_MSG_KEXDH_GEX_GROUP) {
  1427. user_error('Expected SSH_MSG_KEX_DH_GEX_GROUP');
  1428. return false;
  1429. }
  1430. if (strlen($response) < 4) {
  1431. return false;
  1432. }
  1433. extract(unpack('NprimeLength', $this->_string_shift($response, 4)));
  1434. $primeBytes = $this->_string_shift($response, $primeLength);
  1435. $prime = new BigInteger($primeBytes, -256);
  1436. if (strlen($response) < 4) {
  1437. return false;
  1438. }
  1439. extract(unpack('NgLength', $this->_string_shift($response, 4)));
  1440. $gBytes = $this->_string_shift($response, $gLength);
  1441. $g = new BigInteger($gBytes, -256);
  1442. $exchange_hash_rfc4419 = pack(
  1443. 'a*Na*Na*',
  1444. $dh_group_sizes_packed,
  1445. $primeLength,
  1446. $primeBytes,
  1447. $gLength,
  1448. $gBytes
  1449. );
  1450. $clientKexInitMessage = NET_SSH2_MSG_KEXDH_GEX_INIT;
  1451. $serverKexReplyMessage = NET_SSH2_MSG_KEXDH_GEX_REPLY;
  1452. } else {
  1453. switch ($kex_algorithm) {
  1454. // see http://tools.ietf.org/html/rfc2409#section-6.2 and
  1455. // http://tools.ietf.org/html/rfc2412, appendex E
  1456. case 'diffie-hellman-group1-sha1':
  1457. $prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' .
  1458. '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' .
  1459. '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' .
  1460. 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF';
  1461. break;
  1462. // see http://tools.ietf.org/html/rfc3526#section-3
  1463. case 'diffie-hellman-group14-sha1':
  1464. $prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' .
  1465. '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' .
  1466. '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' .
  1467. 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' .
  1468. '98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' .
  1469. '9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' .
  1470. 'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' .
  1471. '3995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF';
  1472. break;
  1473. }
  1474. // For both diffie-hellman-group1-sha1 and diffie-hellman-group14-sha1
  1475. // the generator field element is 2 (decimal) and the hash function is sha1.
  1476. $g = new BigInteger(2);
  1477. $prime = new BigInteger($prime, 16);
  1478. $clientKexInitMessage = NET_SSH2_MSG_KEXDH_INIT;
  1479. $serverKexReplyMessage = NET_SSH2_MSG_KEXDH_REPLY;
  1480. }
  1481. switch ($kex_algorithm) {
  1482. case 'diffie-hellman-group-exchange-sha256':
  1483. $kexHash = new Hash('sha256');
  1484. break;
  1485. default:
  1486. $kexHash = new Hash('sha1');
  1487. }
  1488. /* To increase the speed of the key exchange, both client and server may
  1489. reduce the size of their private exponents. It should be at least
  1490. twice as long as the key material that is generated from the shared
  1491. secret. For more details, see the paper by van Oorschot and Wiener
  1492. [VAN-OORSCHOT].
  1493. -- http://tools.ietf.org/html/rfc4419#section-6.2 */
  1494. $one = new BigInteger(1);
  1495. $keyLength = min($kexHash->getLength(), max($encryptKeyLength, $decryptKeyLength));
  1496. $max = $one->bitwise_leftShift(16 * $keyLength); // 2 * 8 * $keyLength
  1497. $max = $max->subtract($one);
  1498. $x = $one->random($one, $max);
  1499. $e = $g->modPow($x, $prime);
  1500. $eBytes = $e->toBytes(true);
  1501. }
  1502. $data = pack('CNa*', $clientKexInitMessage, strlen($eBytes), $eBytes);
  1503. if (!$this->_send_binary_packet($data)) {
  1504. user_error('Connection closed by server');
  1505. return false;
  1506. }
  1507. $response = $this->_get_binary_packet();
  1508. if ($response === false) {
  1509. user_error('Connection closed by server');
  1510. return false;
  1511. }
  1512. if (!strlen($response)) {
  1513. return false;
  1514. }
  1515. extract(unpack('Ctype', $this->_string_shift($response, 1)));
  1516. if ($type != $serverKexReplyMessage) {
  1517. user_error('Expected SSH_MSG_KEXDH_REPLY');
  1518. return false;
  1519. }
  1520. if (strlen($response) < 4) {
  1521. return false;
  1522. }
  1523. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  1524. $this->server_public_host_key = $server_public_host_key = $this->_string_shift($response, $temp['length']);
  1525. if (strlen($server_public_host_key) < 4) {
  1526. return false;
  1527. }
  1528. $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
  1529. $public_key_format = $this->_string_shift($server_public_host_key, $temp['length']);
  1530. if (strlen($response) < 4) {
  1531. return false;
  1532. }
  1533. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  1534. $fBytes = $this->_string_shift($response, $temp['length']);
  1535. if (strlen($response) < 4) {
  1536. return false;
  1537. }
  1538. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  1539. $this->signature = $this->_string_shift($response, $temp['length']);
  1540. if (strlen($this->signature) < 4) {
  1541. return false;
  1542. }
  1543. $temp = unpack('Nlength', $this->_string_shift($this->signature, 4));
  1544. $this->signature_format = $this->_string_shift($this->signature, $temp['length']);
  1545. if ($kex_algorithm === 'curve25519-sha256@libssh.org') {
  1546. if (strlen($fBytes) !== 32) {
  1547. user_error('Received curve25519 public key of invalid length.');
  1548. return false;
  1549. }
  1550. $key = new BigInteger(\Sodium\crypto_scalarmult($x, $fBytes), 256);
  1551. \Sodium\memzero($x);
  1552. } else {
  1553. $f = new BigInteger($fBytes, -256);
  1554. $key = $f->modPow($x, $prime);
  1555. }
  1556. $keyBytes = $key->toBytes(true);
  1557. $this->exchange_hash = pack(
  1558. 'Na*Na*Na*Na*Na*a*Na*Na*Na*',
  1559. strlen($this->identifier),
  1560. $this->identifier,
  1561. strlen($this->server_identifier),
  1562. $this->server_identifier,
  1563. strlen($kexinit_payload_client),
  1564. $kexinit_payload_client,
  1565. strlen($kexinit_payload_server),
  1566. $kexinit_payload_server,
  1567. strlen($this->server_public_host_key),
  1568. $this->server_public_host_key,
  1569. $exchange_hash_rfc4419,
  1570. strlen($eBytes),
  1571. $eBytes,
  1572. strlen($fBytes),
  1573. $fBytes,
  1574. strlen($keyBytes),
  1575. $keyBytes
  1576. );
  1577. $this->exchange_hash = $kexHash->hash($this->exchange_hash);
  1578. if ($this->session_id === false) {
  1579. $this->session_id = $this->exchange_hash;
  1580. }
  1581. $server_host_key_algorithm = $this->_array_intersect_first($server_host_key_algorithms, $this->server_host_key_algorithms);
  1582. if ($server_host_key_algorithm === false) {
  1583. user_error('No compatible server host key algorithms found');
  1584. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  1585. }
  1586. if ($public_key_format != $server_host_key_algorithm || $this->signature_format != $server_host_key_algorithm) {
  1587. user_error('Server Host Key Algorithm Mismatch');
  1588. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  1589. }
  1590. $packet = pack(
  1591. 'C',
  1592. NET_SSH2_MSG_NEWKEYS
  1593. );
  1594. if (!$this->_send_binary_packet($packet)) {
  1595. return false;
  1596. }
  1597. $response = $this->_get_binary_packet();
  1598. if ($response === false) {
  1599. user_error('Connection closed by server');
  1600. return false;
  1601. }
  1602. if (!strlen($response)) {
  1603. return false;
  1604. }
  1605. extract(unpack('Ctype', $this->_string_shift($response, 1)));
  1606. if ($type != NET_SSH2_MSG_NEWKEYS) {
  1607. user_error('Expected SSH_MSG_NEWKEYS');
  1608. return false;
  1609. }
  1610. $this->decrypt_algorithm = $decrypt;
  1611. $keyBytes = pack('Na*', strlen($keyBytes), $keyBytes);
  1612. $this->encrypt = $this->_encryption_algorithm_to_crypt_instance($encrypt);
  1613. if ($this->encrypt) {
  1614. if ($this->crypto_engine) {
  1615. $this->encrypt->setEngine($this->crypto_engine);
  1616. }
  1617. if ($this->encrypt->block_size) {
  1618. $this->encrypt_block_size = $this->encrypt->block_size;
  1619. }
  1620. $this->encrypt->enableContinuousBuffer();
  1621. $this->encrypt->disablePadding();
  1622. $iv = $kexHash->hash($keyBytes . $this->exchange_hash . 'A' . $this->session_id);
  1623. while ($this->encrypt_block_size > strlen($iv)) {
  1624. $iv.= $kexHash->hash($keyBytes . $this->exchange_hash . $iv);
  1625. }
  1626. $this->encrypt->setIV(substr($iv, 0, $this->encrypt_block_size));
  1627. $key = $kexHash->hash($keyBytes . $this->exchange_hash . 'C' . $this->session_id);
  1628. while ($encryptKeyLength > strlen($key)) {
  1629. $key.= $kexHash->hash($keyBytes . $this->exchange_hash . $key);
  1630. }
  1631. $this->encrypt->setKey(substr($key, 0, $encryptKeyLength));
  1632. }
  1633. $this->decrypt = $this->_encryption_algorithm_to_crypt_instance($decrypt);
  1634. if ($this->decrypt) {
  1635. if ($this->crypto_engine) {
  1636. $this->decrypt->setEngine($this->crypto_engine);
  1637. }
  1638. if ($this->decrypt->block_size) {
  1639. $this->decrypt_block_size = $this->decrypt->block_size;
  1640. }
  1641. $this->decrypt->enableContinuousBuffer();
  1642. $this->decrypt->disablePadding();
  1643. $iv = $kexHash->hash($keyBytes . $this->exchange_hash . 'B' . $this->session_id);
  1644. while ($this->decrypt_block_size > strlen($iv)) {
  1645. $iv.= $kexHash->hash($keyBytes . $this->exchange_hash . $iv);
  1646. }
  1647. $this->decrypt->setIV(substr($iv, 0, $this->decrypt_block_size));
  1648. $key = $kexHash->hash($keyBytes . $this->exchange_hash . 'D' . $this->session_id);
  1649. while ($decryptKeyLength > strlen($key)) {
  1650. $key.= $kexHash->hash($keyBytes . $this->exchange_hash . $key);
  1651. }
  1652. $this->decrypt->setKey(substr($key, 0, $decryptKeyLength));
  1653. }
  1654. /* The "arcfour128" algorithm is the RC4 cipher, as described in
  1655. [SCHNEIER], using a 128-bit key. The first 1536 bytes of keystream
  1656. generated by the cipher MUST be discarded, and the first byte of the
  1657. first encrypted packet MUST be encrypted using the 1537th byte of
  1658. keystream.
  1659. -- http://tools.ietf.org/html/rfc4345#section-4 */
  1660. if ($encrypt == 'arcfour128' || $encrypt == 'arcfour256') {
  1661. $this->encrypt->encrypt(str_repeat("\0", 1536));
  1662. }
  1663. if ($decrypt == 'arcfour128' || $decrypt == 'arcfour256') {
  1664. $this->decrypt->decrypt(str_repeat("\0", 1536));
  1665. }
  1666. $mac_algorithm = $this->_array_intersect_first($mac_algorithms, $this->mac_algorithms_client_to_server);
  1667. if ($mac_algorithm === false) {
  1668. user_error('No compatible client to server message authentication algorithms found');
  1669. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  1670. }
  1671. $createKeyLength = 0; // ie. $mac_algorithm == 'none'
  1672. switch ($mac_algorithm) {
  1673. case 'hmac-sha2-256':
  1674. $this->hmac_create = new Hash('sha256');
  1675. $createKeyLength = 32;
  1676. break;
  1677. case 'hmac-sha1':
  1678. $this->hmac_create = new Hash('sha1');
  1679. $createKeyLength = 20;
  1680. break;
  1681. case 'hmac-sha1-96':
  1682. $this->hmac_create = new Hash('sha1-96');
  1683. $createKeyLength = 20;
  1684. break;
  1685. case 'hmac-md5':
  1686. $this->hmac_create = new Hash('md5');
  1687. $createKeyLength = 16;
  1688. break;
  1689. case 'hmac-md5-96':
  1690. $this->hmac_create = new Hash('md5-96');
  1691. $createKeyLength = 16;
  1692. }
  1693. $mac_algorithm = $this->_array_intersect_first($mac_algorithms, $this->mac_algorithms_server_to_client);
  1694. if ($mac_algorithm === false) {
  1695. user_error('No compatible server to client message authentication algorithms found');
  1696. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  1697. }
  1698. $checkKeyLength = 0;
  1699. $this->hmac_size = 0;
  1700. switch ($mac_algorithm) {
  1701. case 'hmac-sha2-256':
  1702. $this->hmac_check = new Hash('sha256');
  1703. $checkKeyLength = 32;
  1704. $this->hmac_size = 32;
  1705. break;
  1706. case 'hmac-sha1':
  1707. $this->hmac_check = new Hash('sha1');
  1708. $checkKeyLength = 20;
  1709. $this->hmac_size = 20;
  1710. break;
  1711. case 'hmac-sha1-96':
  1712. $this->hmac_check = new Hash('sha1-96');
  1713. $checkKeyLength = 20;
  1714. $this->hmac_size = 12;
  1715. break;
  1716. case 'hmac-md5':
  1717. $this->hmac_check = new Hash('md5');
  1718. $checkKeyLength = 16;
  1719. $this->hmac_size = 16;
  1720. break;
  1721. case 'hmac-md5-96':
  1722. $this->hmac_check = new Hash('md5-96');
  1723. $checkKeyLength = 16;
  1724. $this->hmac_size = 12;
  1725. }
  1726. $key = $kexHash->hash($keyBytes . $this->exchange_hash . 'E' . $this->session_id);
  1727. while ($createKeyLength > strlen($key)) {
  1728. $key.= $kexHash->hash($keyBytes . $this->exchange_hash . $key);
  1729. }
  1730. $this->hmac_create->setKey(substr($key, 0, $createKeyLength));
  1731. $key = $kexHash->hash($keyBytes . $this->exchange_hash . 'F' . $this->session_id);
  1732. while ($checkKeyLength > strlen($key)) {
  1733. $key.= $kexHash->hash($keyBytes . $this->exchange_hash . $key);
  1734. }
  1735. $this->hmac_check->setKey(substr($key, 0, $checkKeyLength));
  1736. $compression_algorithm = $this->_array_intersect_first($compression_algorithms, $this->compression_algorithms_server_to_client);
  1737. if ($compression_algorithm === false) {
  1738. user_error('No compatible server to client compression algorithms found');
  1739. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  1740. }
  1741. $this->decompress = $compression_algorithm == 'zlib';
  1742. $compression_algorithm = $this->_array_intersect_first($compression_algorithms, $this->compression_algorithms_client_to_server);
  1743. if ($compression_algorithm === false) {
  1744. user_error('No compatible client to server compression algorithms found');
  1745. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  1746. }
  1747. $this->compress = $compression_algorithm == 'zlib';
  1748. return true;
  1749. }
  1750. /**
  1751. * Maps an encryption algorithm name to the number of key bytes.
  1752. *
  1753. * @param string $algorithm Name of the encryption algorithm
  1754. * @return int|null Number of bytes as an integer or null for unknown
  1755. * @access private
  1756. */
  1757. function _encryption_algorithm_to_key_size($algorithm)
  1758. {
  1759. if ($this->bad_key_size_fix && $this->_bad_algorithm_candidate($algorithm)) {
  1760. return 16;
  1761. }
  1762. switch ($algorithm) {
  1763. case 'none':
  1764. return 0;
  1765. case 'aes128-cbc':
  1766. case 'aes128-ctr':
  1767. case 'arcfour':
  1768. case 'arcfour128':
  1769. case 'blowfish-cbc':
  1770. case 'blowfish-ctr':
  1771. case 'twofish128-cbc':
  1772. case 'twofish128-ctr':
  1773. return 16;
  1774. case '3des-cbc':
  1775. case '3des-ctr':
  1776. case 'aes192-cbc':
  1777. case 'aes192-ctr':
  1778. case 'twofish192-cbc':
  1779. case 'twofish192-ctr':
  1780. return 24;
  1781. case 'aes256-cbc':
  1782. case 'aes256-ctr':
  1783. case 'arcfour256':
  1784. case 'twofish-cbc':
  1785. case 'twofish256-cbc':
  1786. case 'twofish256-ctr':
  1787. return 32;
  1788. }
  1789. return null;
  1790. }
  1791. /**
  1792. * Maps an encryption algorithm name to an instance of a subclass of
  1793. * \phpseclib\Crypt\Base.
  1794. *
  1795. * @param string $algorithm Name of the encryption algorithm
  1796. * @return mixed Instance of \phpseclib\Crypt\Base or null for unknown
  1797. * @access private
  1798. */
  1799. function _encryption_algorithm_to_crypt_instance($algorithm)
  1800. {
  1801. switch ($algorithm) {
  1802. case '3des-cbc':
  1803. return new TripleDES();
  1804. case '3des-ctr':
  1805. return new TripleDES(Base::MODE_CTR);
  1806. case 'aes256-cbc':
  1807. case 'aes192-cbc':
  1808. case 'aes128-cbc':
  1809. return new Rijndael();
  1810. case 'aes256-ctr':
  1811. case 'aes192-ctr':
  1812. case 'aes128-ctr':
  1813. return new Rijndael(Base::MODE_CTR);
  1814. case 'blowfish-cbc':
  1815. return new Blowfish();
  1816. case 'blowfish-ctr':
  1817. return new Blowfish(Base::MODE_CTR);
  1818. case 'twofish128-cbc':
  1819. case 'twofish192-cbc':
  1820. case 'twofish256-cbc':
  1821. case 'twofish-cbc':
  1822. return new Twofish();
  1823. case 'twofish128-ctr':
  1824. case 'twofish192-ctr':
  1825. case 'twofish256-ctr':
  1826. return new Twofish(Base::MODE_CTR);
  1827. case 'arcfour':
  1828. case 'arcfour128':
  1829. case 'arcfour256':
  1830. return new RC4();
  1831. }
  1832. return null;
  1833. }
  1834. /*
  1835. * Tests whether or not proposed algorithm has a potential for issues
  1836. *
  1837. * @link https://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/ssh2-aesctr-openssh.html
  1838. * @link https://bugzilla.mindrot.org/show_bug.cgi?id=1291
  1839. * @param string $algorithm Name of the encryption algorithm
  1840. * @return bool
  1841. * @access private
  1842. */
  1843. function _bad_algorithm_candidate($algorithm)
  1844. {
  1845. switch ($algorithm) {
  1846. case 'arcfour256':
  1847. case 'aes192-ctr':
  1848. case 'aes256-ctr':
  1849. return true;
  1850. }
  1851. return false;
  1852. }
  1853. /**
  1854. * Login
  1855. *
  1856. * The $password parameter can be a plaintext password, a \phpseclib\Crypt\RSA object or an array
  1857. *
  1858. * @param string $username
  1859. * @param mixed $password
  1860. * @param mixed $...
  1861. * @return bool
  1862. * @see self::_login()
  1863. * @access public
  1864. */
  1865. function login($username)
  1866. {
  1867. $args = func_get_args();
  1868. return call_user_func_array(array(&$this, '_login'), $args);
  1869. }
  1870. /**
  1871. * Login Helper
  1872. *
  1873. * @param string $username
  1874. * @param mixed $password
  1875. * @param mixed $...
  1876. * @return bool
  1877. * @see self::_login_helper()
  1878. * @access private
  1879. */
  1880. function _login($username)
  1881. {
  1882. if (!($this->bitmap & self::MASK_CONSTRUCTOR)) {
  1883. if (!$this->_connect()) {
  1884. return false;
  1885. }
  1886. }
  1887. $args = array_slice(func_get_args(), 1);
  1888. if (empty($args)) {
  1889. return $this->_login_helper($username);
  1890. }
  1891. foreach ($args as $arg) {
  1892. if ($this->_login_helper($username, $arg)) {
  1893. return true;
  1894. }
  1895. }
  1896. return false;
  1897. }
  1898. /**
  1899. * Login Helper
  1900. *
  1901. * @param string $username
  1902. * @param string $password
  1903. * @return bool
  1904. * @access private
  1905. * @internal It might be worthwhile, at some point, to protect against {@link http://tools.ietf.org/html/rfc4251#section-9.3.9 traffic analysis}
  1906. * by sending dummy SSH_MSG_IGNORE messages.
  1907. */
  1908. function _login_helper($username, $password = null)
  1909. {
  1910. if (!($this->bitmap & self::MASK_CONNECTED)) {
  1911. return false;
  1912. }
  1913. if (!($this->bitmap & self::MASK_LOGIN_REQ)) {
  1914. $packet = pack(
  1915. 'CNa*',
  1916. NET_SSH2_MSG_SERVICE_REQUEST,
  1917. strlen('ssh-userauth'),
  1918. 'ssh-userauth'
  1919. );
  1920. if (!$this->_send_binary_packet($packet)) {
  1921. return false;
  1922. }
  1923. $response = $this->_get_binary_packet();
  1924. if ($response === false) {
  1925. if ($this->retry_connect) {
  1926. $this->retry_connect = false;
  1927. if (!$this->_connect()) {
  1928. return false;
  1929. }
  1930. return $this->_login_helper($username, $password);
  1931. }
  1932. user_error('Connection closed by server');
  1933. return false;
  1934. }
  1935. if (strlen($response) < 4) {
  1936. return false;
  1937. }
  1938. extract(unpack('Ctype', $this->_string_shift($response, 1)));
  1939. if ($type != NET_SSH2_MSG_SERVICE_ACCEPT) {
  1940. user_error('Expected SSH_MSG_SERVICE_ACCEPT');
  1941. return false;
  1942. }
  1943. $this->bitmap |= self::MASK_LOGIN_REQ;
  1944. }
  1945. if (strlen($this->last_interactive_response)) {
  1946. return !is_string($password) && !is_array($password) ? false : $this->_keyboard_interactive_process($password);
  1947. }
  1948. if ($password instanceof RSA) {
  1949. return $this->_privatekey_login($username, $password);
  1950. } elseif ($password instanceof Agent) {
  1951. return $this->_ssh_agent_login($username, $password);
  1952. }
  1953. if (is_array($password)) {
  1954. if ($this->_keyboard_interactive_login($username, $password)) {
  1955. $this->bitmap |= self::MASK_LOGIN;
  1956. return true;
  1957. }
  1958. return false;
  1959. }
  1960. if (!isset($password)) {
  1961. $packet = pack(
  1962. 'CNa*Na*Na*',
  1963. NET_SSH2_MSG_USERAUTH_REQUEST,
  1964. strlen($username),
  1965. $username,
  1966. strlen('ssh-connection'),
  1967. 'ssh-connection',
  1968. strlen('none'),
  1969. 'none'
  1970. );
  1971. if (!$this->_send_binary_packet($packet)) {
  1972. return false;
  1973. }
  1974. $response = $this->_get_binary_packet();
  1975. if ($response === false) {
  1976. user_error('Connection closed by server');
  1977. return false;
  1978. }
  1979. if (!strlen($response)) {
  1980. return false;
  1981. }
  1982. extract(unpack('Ctype', $this->_string_shift($response, 1)));
  1983. switch ($type) {
  1984. case NET_SSH2_MSG_USERAUTH_SUCCESS:
  1985. $this->bitmap |= self::MASK_LOGIN;
  1986. return true;
  1987. //case NET_SSH2_MSG_USERAUTH_FAILURE:
  1988. default:
  1989. return false;
  1990. }
  1991. }
  1992. $packet = pack(
  1993. 'CNa*Na*Na*CNa*',
  1994. NET_SSH2_MSG_USERAUTH_REQUEST,
  1995. strlen($username),
  1996. $username,
  1997. strlen('ssh-connection'),
  1998. 'ssh-connection',
  1999. strlen('password'),
  2000. 'password',
  2001. 0,
  2002. strlen($password),
  2003. $password
  2004. );
  2005. // remove the username and password from the logged packet
  2006. if (!defined('NET_SSH2_LOGGING')) {
  2007. $logged = null;
  2008. } else {
  2009. $logged = pack(
  2010. 'CNa*Na*Na*CNa*',
  2011. NET_SSH2_MSG_USERAUTH_REQUEST,
  2012. strlen('username'),
  2013. 'username',
  2014. strlen('ssh-connection'),
  2015. 'ssh-connection',
  2016. strlen('password'),
  2017. 'password',
  2018. 0,
  2019. strlen('password'),
  2020. 'password'
  2021. );
  2022. }
  2023. if (!$this->_send_binary_packet($packet, $logged)) {
  2024. return false;
  2025. }
  2026. $response = $this->_get_binary_packet();
  2027. if ($response === false) {
  2028. user_error('Connection closed by server');
  2029. return false;
  2030. }
  2031. if (!strlen($response)) {
  2032. return false;
  2033. }
  2034. extract(unpack('Ctype', $this->_string_shift($response, 1)));
  2035. switch ($type) {
  2036. case NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ: // in theory, the password can be changed
  2037. if (defined('NET_SSH2_LOGGING')) {
  2038. $this->message_number_log[count($this->message_number_log) - 1] = 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ';
  2039. }
  2040. if (strlen($response) < 4) {
  2041. return false;
  2042. }
  2043. extract(unpack('Nlength', $this->_string_shift($response, 4)));
  2044. $this->errors[] = 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ: ' . utf8_decode($this->_string_shift($response, $length));
  2045. return $this->_disconnect(NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER);
  2046. case NET_SSH2_MSG_USERAUTH_FAILURE:
  2047. // can we use keyboard-interactive authentication? if not then either the login is bad or the server employees
  2048. // multi-factor authentication
  2049. if (strlen($response) < 4) {
  2050. return false;
  2051. }
  2052. extract(unpack('Nlength', $this->_string_shift($response, 4)));
  2053. $auth_methods = explode(',', $this->_string_shift($response, $length));
  2054. if (!strlen($response)) {
  2055. return false;
  2056. }
  2057. extract(unpack('Cpartial_success', $this->_string_shift($response, 1)));
  2058. $partial_success = $partial_success != 0;
  2059. if (!$partial_success && in_array('keyboard-interactive', $auth_methods)) {
  2060. if ($this->_keyboard_interactive_login($username, $password)) {
  2061. $this->bitmap |= self::MASK_LOGIN;
  2062. return true;
  2063. }
  2064. return false;
  2065. }
  2066. return false;
  2067. case NET_SSH2_MSG_USERAUTH_SUCCESS:
  2068. $this->bitmap |= self::MASK_LOGIN;
  2069. return true;
  2070. }
  2071. return false;
  2072. }
  2073. /**
  2074. * Login via keyboard-interactive authentication
  2075. *
  2076. * See {@link http://tools.ietf.org/html/rfc4256 RFC4256} for details. This is not a full-featured keyboard-interactive authenticator.
  2077. *
  2078. * @param string $username
  2079. * @param string $password
  2080. * @return bool
  2081. * @access private
  2082. */
  2083. function _keyboard_interactive_login($username, $password)
  2084. {
  2085. $packet = pack(
  2086. 'CNa*Na*Na*Na*Na*',
  2087. NET_SSH2_MSG_USERAUTH_REQUEST,
  2088. strlen($username),
  2089. $username,
  2090. strlen('ssh-connection'),
  2091. 'ssh-connection',
  2092. strlen('keyboard-interactive'),
  2093. 'keyboard-interactive',
  2094. 0,
  2095. '',
  2096. 0,
  2097. ''
  2098. );
  2099. if (!$this->_send_binary_packet($packet)) {
  2100. return false;
  2101. }
  2102. return $this->_keyboard_interactive_process($password);
  2103. }
  2104. /**
  2105. * Handle the keyboard-interactive requests / responses.
  2106. *
  2107. * @param string $responses...
  2108. * @return bool
  2109. * @access private
  2110. */
  2111. function _keyboard_interactive_process()
  2112. {
  2113. $responses = func_get_args();
  2114. if (strlen($this->last_interactive_response)) {
  2115. $response = $this->last_interactive_response;
  2116. } else {
  2117. $orig = $response = $this->_get_binary_packet();
  2118. if ($response === false) {
  2119. user_error('Connection closed by server');
  2120. return false;
  2121. }
  2122. }
  2123. if (!strlen($response)) {
  2124. return false;
  2125. }
  2126. extract(unpack('Ctype', $this->_string_shift($response, 1)));
  2127. switch ($type) {
  2128. case NET_SSH2_MSG_USERAUTH_INFO_REQUEST:
  2129. if (strlen($response) < 4) {
  2130. return false;
  2131. }
  2132. extract(unpack('Nlength', $this->_string_shift($response, 4)));
  2133. $this->_string_shift($response, $length); // name; may be empty
  2134. if (strlen($response) < 4) {
  2135. return false;
  2136. }
  2137. extract(unpack('Nlength', $this->_string_shift($response, 4)));
  2138. $this->_string_shift($response, $length); // instruction; may be empty
  2139. if (strlen($response) < 4) {
  2140. return false;
  2141. }
  2142. extract(unpack('Nlength', $this->_string_shift($response, 4)));
  2143. $this->_string_shift($response, $length); // language tag; may be empty
  2144. if (strlen($response) < 4) {
  2145. return false;
  2146. }
  2147. extract(unpack('Nnum_prompts', $this->_string_shift($response, 4)));
  2148. for ($i = 0; $i < count($responses); $i++) {
  2149. if (is_array($responses[$i])) {
  2150. foreach ($responses[$i] as $key => $value) {
  2151. $this->keyboard_requests_responses[$key] = $value;
  2152. }
  2153. unset($responses[$i]);
  2154. }
  2155. }
  2156. $responses = array_values($responses);
  2157. if (isset($this->keyboard_requests_responses)) {
  2158. for ($i = 0; $i < $num_prompts; $i++) {
  2159. if (strlen($response) < 4) {
  2160. return false;
  2161. }
  2162. extract(unpack('Nlength', $this->_string_shift($response, 4)));
  2163. // prompt - ie. "Password: "; must not be empty
  2164. $prompt = $this->_string_shift($response, $length);
  2165. //$echo = $this->_string_shift($response) != chr(0);
  2166. foreach ($this->keyboard_requests_responses as $key => $value) {
  2167. if (substr($prompt, 0, strlen($key)) == $key) {
  2168. $responses[] = $value;
  2169. break;
  2170. }
  2171. }
  2172. }
  2173. }
  2174. // see http://tools.ietf.org/html/rfc4256#section-3.2
  2175. if (strlen($this->last_interactive_response)) {
  2176. $this->last_interactive_response = '';
  2177. } elseif (defined('NET_SSH2_LOGGING')) {
  2178. $this->message_number_log[count($this->message_number_log) - 1] = str_replace(
  2179. 'UNKNOWN',
  2180. 'NET_SSH2_MSG_USERAUTH_INFO_REQUEST',
  2181. $this->message_number_log[count($this->message_number_log) - 1]
  2182. );
  2183. }
  2184. if (!count($responses) && $num_prompts) {
  2185. $this->last_interactive_response = $orig;
  2186. return false;
  2187. }
  2188. /*
  2189. After obtaining the requested information from the user, the client
  2190. MUST respond with an SSH_MSG_USERAUTH_INFO_RESPONSE message.
  2191. */
  2192. // see http://tools.ietf.org/html/rfc4256#section-3.4
  2193. $packet = $logged = pack('CN', NET_SSH2_MSG_USERAUTH_INFO_RESPONSE, count($responses));
  2194. for ($i = 0; $i < count($responses); $i++) {
  2195. $packet.= pack('Na*', strlen($responses[$i]), $responses[$i]);
  2196. $logged.= pack('Na*', strlen('dummy-answer'), 'dummy-answer');
  2197. }
  2198. if (!$this->_send_binary_packet($packet, $logged)) {
  2199. return false;
  2200. }
  2201. if (defined('NET_SSH2_LOGGING') && NET_SSH2_LOGGING == self::LOG_COMPLEX) {
  2202. $this->message_number_log[count($this->message_number_log) - 1] = str_replace(
  2203. 'UNKNOWN',
  2204. 'NET_SSH2_MSG_USERAUTH_INFO_RESPONSE',
  2205. $this->message_number_log[count($this->message_number_log) - 1]
  2206. );
  2207. }
  2208. /*
  2209. After receiving the response, the server MUST send either an
  2210. SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, or another
  2211. SSH_MSG_USERAUTH_INFO_REQUEST message.
  2212. */
  2213. // maybe phpseclib should force close the connection after x request / responses? unless something like that is done
  2214. // there could be an infinite loop of request / responses.
  2215. return $this->_keyboard_interactive_process();
  2216. case NET_SSH2_MSG_USERAUTH_SUCCESS:
  2217. return true;
  2218. case NET_SSH2_MSG_USERAUTH_FAILURE:
  2219. return false;
  2220. }
  2221. return false;
  2222. }
  2223. /**
  2224. * Login with an ssh-agent provided key
  2225. *
  2226. * @param string $username
  2227. * @param \phpseclib\System\SSH\Agent $agent
  2228. * @return bool
  2229. * @access private
  2230. */
  2231. function _ssh_agent_login($username, $agent)
  2232. {
  2233. $this->agent = $agent;
  2234. $keys = $agent->requestIdentities();
  2235. foreach ($keys as $key) {
  2236. if ($this->_privatekey_login($username, $key)) {
  2237. return true;
  2238. }
  2239. }
  2240. return false;
  2241. }
  2242. /**
  2243. * Login with an RSA private key
  2244. *
  2245. * @param string $username
  2246. * @param \phpseclib\Crypt\RSA $password
  2247. * @return bool
  2248. * @access private
  2249. * @internal It might be worthwhile, at some point, to protect against {@link http://tools.ietf.org/html/rfc4251#section-9.3.9 traffic analysis}
  2250. * by sending dummy SSH_MSG_IGNORE messages.
  2251. */
  2252. function _privatekey_login($username, $privatekey)
  2253. {
  2254. // see http://tools.ietf.org/html/rfc4253#page-15
  2255. $publickey = $privatekey->getPublicKey(RSA::PUBLIC_FORMAT_RAW);
  2256. if ($publickey === false) {
  2257. return false;
  2258. }
  2259. $publickey = array(
  2260. 'e' => $publickey['e']->toBytes(true),
  2261. 'n' => $publickey['n']->toBytes(true)
  2262. );
  2263. $publickey = pack(
  2264. 'Na*Na*Na*',
  2265. strlen('ssh-rsa'),
  2266. 'ssh-rsa',
  2267. strlen($publickey['e']),
  2268. $publickey['e'],
  2269. strlen($publickey['n']),
  2270. $publickey['n']
  2271. );
  2272. $part1 = pack(
  2273. 'CNa*Na*Na*',
  2274. NET_SSH2_MSG_USERAUTH_REQUEST,
  2275. strlen($username),
  2276. $username,
  2277. strlen('ssh-connection'),
  2278. 'ssh-connection',
  2279. strlen('publickey'),
  2280. 'publickey'
  2281. );
  2282. $part2 = pack('Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publickey), $publickey);
  2283. $packet = $part1 . chr(0) . $part2;
  2284. if (!$this->_send_binary_packet($packet)) {
  2285. return false;
  2286. }
  2287. $response = $this->_get_binary_packet();
  2288. if ($response === false) {
  2289. user_error('Connection closed by server');
  2290. return false;
  2291. }
  2292. if (!strlen($response)) {
  2293. return false;
  2294. }
  2295. extract(unpack('Ctype', $this->_string_shift($response, 1)));
  2296. switch ($type) {
  2297. case NET_SSH2_MSG_USERAUTH_FAILURE:
  2298. if (strlen($response) < 4) {
  2299. return false;
  2300. }
  2301. extract(unpack('Nlength', $this->_string_shift($response, 4)));
  2302. $this->errors[] = 'SSH_MSG_USERAUTH_FAILURE: ' . $this->_string_shift($response, $length);
  2303. return false;
  2304. case NET_SSH2_MSG_USERAUTH_PK_OK:
  2305. // we'll just take it on faith that the public key blob and the public key algorithm name are as
  2306. // they should be
  2307. if (defined('NET_SSH2_LOGGING') && NET_SSH2_LOGGING == self::LOG_COMPLEX) {
  2308. $this->message_number_log[count($this->message_number_log) - 1] = str_replace(
  2309. 'UNKNOWN',
  2310. 'NET_SSH2_MSG_USERAUTH_PK_OK',
  2311. $this->message_number_log[count($this->message_number_log) - 1]
  2312. );
  2313. }
  2314. }
  2315. $packet = $part1 . chr(1) . $part2;
  2316. $privatekey->setSignatureMode(RSA::SIGNATURE_PKCS1);
  2317. $signature = $privatekey->sign(pack('Na*a*', strlen($this->session_id), $this->session_id, $packet));
  2318. $signature = pack('Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($signature), $signature);
  2319. $packet.= pack('Na*', strlen($signature), $signature);
  2320. if (!$this->_send_binary_packet($packet)) {
  2321. return false;
  2322. }
  2323. $response = $this->_get_binary_packet();
  2324. if ($response === false) {
  2325. user_error('Connection closed by server');
  2326. return false;
  2327. }
  2328. if (!strlen($response)) {
  2329. return false;
  2330. }
  2331. extract(unpack('Ctype', $this->_string_shift($response, 1)));
  2332. switch ($type) {
  2333. case NET_SSH2_MSG_USERAUTH_FAILURE:
  2334. // either the login is bad or the server employs multi-factor authentication
  2335. return false;
  2336. case NET_SSH2_MSG_USERAUTH_SUCCESS:
  2337. $this->bitmap |= self::MASK_LOGIN;
  2338. return true;
  2339. }
  2340. return false;
  2341. }
  2342. /**
  2343. * Set Timeout
  2344. *
  2345. * $ssh->exec('ping 127.0.0.1'); on a Linux host will never return and will run indefinitely. setTimeout() makes it so it'll timeout.
  2346. * Setting $timeout to false or 0 will mean there is no timeout.
  2347. *
  2348. * @param mixed $timeout
  2349. * @access public
  2350. */
  2351. function setTimeout($timeout)
  2352. {
  2353. $this->timeout = $this->curTimeout = $timeout;
  2354. }
  2355. /**
  2356. * Get the output from stdError
  2357. *
  2358. * @access public
  2359. */
  2360. function getStdError()
  2361. {
  2362. return $this->stdErrorLog;
  2363. }
  2364. /**
  2365. * Execute Command
  2366. *
  2367. * If $callback is set to false then \phpseclib\Net\SSH2::_get_channel_packet(self::CHANNEL_EXEC) will need to be called manually.
  2368. * In all likelihood, this is not a feature you want to be taking advantage of.
  2369. *
  2370. * @param string $command
  2371. * @param Callback $callback
  2372. * @return string
  2373. * @access public
  2374. */
  2375. function exec($command, $callback = null)
  2376. {
  2377. $this->curTimeout = $this->timeout;
  2378. $this->is_timeout = false;
  2379. $this->stdErrorLog = '';
  2380. if (!$this->isAuthenticated()) {
  2381. return false;
  2382. }
  2383. if ($this->in_request_pty_exec) {
  2384. user_error('If you want to run multiple exec()\'s you will need to disable (and re-enable if appropriate) a PTY for each one.');
  2385. return false;
  2386. }
  2387. // RFC4254 defines the (client) window size as "bytes the other party can send before it must wait for the window to
  2388. // be adjusted". 0x7FFFFFFF is, at 2GB, the max size. technically, it should probably be decremented, but,
  2389. // honestly, if you're transferring more than 2GB, you probably shouldn't be using phpseclib, anyway.
  2390. // see http://tools.ietf.org/html/rfc4254#section-5.2 for more info
  2391. $this->window_size_server_to_client[self::CHANNEL_EXEC] = $this->window_size;
  2392. // 0x8000 is the maximum max packet size, per http://tools.ietf.org/html/rfc4253#section-6.1, although since PuTTy
  2393. // uses 0x4000, that's what will be used here, as well.
  2394. $packet_size = 0x4000;
  2395. $packet = pack(
  2396. 'CNa*N3',
  2397. NET_SSH2_MSG_CHANNEL_OPEN,
  2398. strlen('session'),
  2399. 'session',
  2400. self::CHANNEL_EXEC,
  2401. $this->window_size_server_to_client[self::CHANNEL_EXEC],
  2402. $packet_size
  2403. );
  2404. if (!$this->_send_binary_packet($packet)) {
  2405. return false;
  2406. }
  2407. $this->channel_status[self::CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_OPEN;
  2408. $response = $this->_get_channel_packet(self::CHANNEL_EXEC);
  2409. if ($response === false) {
  2410. return false;
  2411. }
  2412. if ($this->request_pty === true) {
  2413. $terminal_modes = pack('C', NET_SSH2_TTY_OP_END);
  2414. $packet = pack(
  2415. 'CNNa*CNa*N5a*',
  2416. NET_SSH2_MSG_CHANNEL_REQUEST,
  2417. $this->server_channels[self::CHANNEL_EXEC],
  2418. strlen('pty-req'),
  2419. 'pty-req',
  2420. 1,
  2421. strlen('vt100'),
  2422. 'vt100',
  2423. $this->windowColumns,
  2424. $this->windowRows,
  2425. 0,
  2426. 0,
  2427. strlen($terminal_modes),
  2428. $terminal_modes
  2429. );
  2430. if (!$this->_send_binary_packet($packet)) {
  2431. return false;
  2432. }
  2433. $response = $this->_get_binary_packet();
  2434. if ($response === false) {
  2435. user_error('Connection closed by server');
  2436. return false;
  2437. }
  2438. if (!strlen($response)) {
  2439. return false;
  2440. }
  2441. list(, $type) = unpack('C', $this->_string_shift($response, 1));
  2442. switch ($type) {
  2443. case NET_SSH2_MSG_CHANNEL_SUCCESS:
  2444. break;
  2445. case NET_SSH2_MSG_CHANNEL_FAILURE:
  2446. default:
  2447. user_error('Unable to request pseudo-terminal');
  2448. return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
  2449. }
  2450. $this->in_request_pty_exec = true;
  2451. }
  2452. // sending a pty-req SSH_MSG_CHANNEL_REQUEST message is unnecessary and, in fact, in most cases, slows things
  2453. // down. the one place where it might be desirable is if you're doing something like \phpseclib\Net\SSH2::exec('ping localhost &').
  2454. // with a pty-req SSH_MSG_CHANNEL_REQUEST, exec() will return immediately and the ping process will then
  2455. // then immediately terminate. without such a request exec() will loop indefinitely. the ping process won't end but
  2456. // neither will your script.
  2457. // although, in theory, the size of SSH_MSG_CHANNEL_REQUEST could exceed the maximum packet size established by
  2458. // SSH_MSG_CHANNEL_OPEN_CONFIRMATION, RFC4254#section-5.1 states that the "maximum packet size" refers to the
  2459. // "maximum size of an individual data packet". ie. SSH_MSG_CHANNEL_DATA. RFC4254#section-5.2 corroborates.
  2460. $packet = pack(
  2461. 'CNNa*CNa*',
  2462. NET_SSH2_MSG_CHANNEL_REQUEST,
  2463. $this->server_channels[self::CHANNEL_EXEC],
  2464. strlen('exec'),
  2465. 'exec',
  2466. 1,
  2467. strlen($command),
  2468. $command
  2469. );
  2470. if (!$this->_send_binary_packet($packet)) {
  2471. return false;
  2472. }
  2473. $this->channel_status[self::CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_REQUEST;
  2474. $response = $this->_get_channel_packet(self::CHANNEL_EXEC);
  2475. if ($response === false) {
  2476. return false;
  2477. }
  2478. $this->channel_status[self::CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_DATA;
  2479. if ($callback === false || $this->in_request_pty_exec) {
  2480. return true;
  2481. }
  2482. $output = '';
  2483. while (true) {
  2484. $temp = $this->_get_channel_packet(self::CHANNEL_EXEC);
  2485. switch (true) {
  2486. case $temp === true:
  2487. return is_callable($callback) ? true : $output;
  2488. case $temp === false:
  2489. return false;
  2490. default:
  2491. if (is_callable($callback)) {
  2492. if (call_user_func($callback, $temp) === true) {
  2493. $this->_close_channel(self::CHANNEL_EXEC);
  2494. return true;
  2495. }
  2496. } else {
  2497. $output.= $temp;
  2498. }
  2499. }
  2500. }
  2501. }
  2502. /**
  2503. * Creates an interactive shell
  2504. *
  2505. * @see self::read()
  2506. * @see self::write()
  2507. * @return bool
  2508. * @access private
  2509. */
  2510. function _initShell()
  2511. {
  2512. if ($this->in_request_pty_exec === true) {
  2513. return true;
  2514. }
  2515. $this->window_size_server_to_client[self::CHANNEL_SHELL] = $this->window_size;
  2516. $packet_size = 0x4000;
  2517. $packet = pack(
  2518. 'CNa*N3',
  2519. NET_SSH2_MSG_CHANNEL_OPEN,
  2520. strlen('session'),
  2521. 'session',
  2522. self::CHANNEL_SHELL,
  2523. $this->window_size_server_to_client[self::CHANNEL_SHELL],
  2524. $packet_size
  2525. );
  2526. if (!$this->_send_binary_packet($packet)) {
  2527. return false;
  2528. }
  2529. $this->channel_status[self::CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_OPEN;
  2530. $response = $this->_get_channel_packet(self::CHANNEL_SHELL);
  2531. if ($response === false) {
  2532. return false;
  2533. }
  2534. $terminal_modes = pack('C', NET_SSH2_TTY_OP_END);
  2535. $packet = pack(
  2536. 'CNNa*CNa*N5a*',
  2537. NET_SSH2_MSG_CHANNEL_REQUEST,
  2538. $this->server_channels[self::CHANNEL_SHELL],
  2539. strlen('pty-req'),
  2540. 'pty-req',
  2541. 1,
  2542. strlen('vt100'),
  2543. 'vt100',
  2544. $this->windowColumns,
  2545. $this->windowRows,
  2546. 0,
  2547. 0,
  2548. strlen($terminal_modes),
  2549. $terminal_modes
  2550. );
  2551. if (!$this->_send_binary_packet($packet)) {
  2552. return false;
  2553. }
  2554. $response = $this->_get_binary_packet();
  2555. if ($response === false) {
  2556. user_error('Connection closed by server');
  2557. return false;
  2558. }
  2559. if (!strlen($response)) {
  2560. return false;
  2561. }
  2562. list(, $type) = unpack('C', $this->_string_shift($response, 1));
  2563. switch ($type) {
  2564. case NET_SSH2_MSG_CHANNEL_SUCCESS:
  2565. // if a pty can't be opened maybe commands can still be executed
  2566. case NET_SSH2_MSG_CHANNEL_FAILURE:
  2567. break;
  2568. default:
  2569. user_error('Unable to request pseudo-terminal');
  2570. return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
  2571. }
  2572. $packet = pack(
  2573. 'CNNa*C',
  2574. NET_SSH2_MSG_CHANNEL_REQUEST,
  2575. $this->server_channels[self::CHANNEL_SHELL],
  2576. strlen('shell'),
  2577. 'shell',
  2578. 1
  2579. );
  2580. if (!$this->_send_binary_packet($packet)) {
  2581. return false;
  2582. }
  2583. $this->channel_status[self::CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_REQUEST;
  2584. $response = $this->_get_channel_packet(self::CHANNEL_SHELL);
  2585. if ($response === false) {
  2586. return false;
  2587. }
  2588. $this->channel_status[self::CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_DATA;
  2589. $this->bitmap |= self::MASK_SHELL;
  2590. return true;
  2591. }
  2592. /**
  2593. * Return the channel to be used with read() / write()
  2594. *
  2595. * @see self::read()
  2596. * @see self::write()
  2597. * @return int
  2598. * @access public
  2599. */
  2600. function _get_interactive_channel()
  2601. {
  2602. switch (true) {
  2603. case $this->in_subsystem:
  2604. return self::CHANNEL_SUBSYSTEM;
  2605. case $this->in_request_pty_exec:
  2606. return self::CHANNEL_EXEC;
  2607. default:
  2608. return self::CHANNEL_SHELL;
  2609. }
  2610. }
  2611. /**
  2612. * Return an available open channel
  2613. *
  2614. * @return int
  2615. * @access public
  2616. */
  2617. function _get_open_channel()
  2618. {
  2619. $channel = self::CHANNEL_EXEC;
  2620. do {
  2621. if (isset($this->channel_status[$channel]) && $this->channel_status[$channel] == NET_SSH2_MSG_CHANNEL_OPEN) {
  2622. return $channel;
  2623. }
  2624. } while ($channel++ < self::CHANNEL_SUBSYSTEM);
  2625. return false;
  2626. }
  2627. /**
  2628. * Returns the output of an interactive shell
  2629. *
  2630. * Returns when there's a match for $expect, which can take the form of a string literal or,
  2631. * if $mode == self::READ_REGEX, a regular expression.
  2632. *
  2633. * @see self::write()
  2634. * @param string $expect
  2635. * @param int $mode
  2636. * @return string
  2637. * @access public
  2638. */
  2639. function read($expect = '', $mode = self::READ_SIMPLE)
  2640. {
  2641. $this->curTimeout = $this->timeout;
  2642. $this->is_timeout = false;
  2643. if (!$this->isAuthenticated()) {
  2644. user_error('Operation disallowed prior to login()');
  2645. return false;
  2646. }
  2647. if (!($this->bitmap & self::MASK_SHELL) && !$this->_initShell()) {
  2648. user_error('Unable to initiate an interactive shell session');
  2649. return false;
  2650. }
  2651. $channel = $this->_get_interactive_channel();
  2652. if ($mode == self::READ_NEXT) {
  2653. return $this->_get_channel_packet($channel);
  2654. }
  2655. $match = $expect;
  2656. while (true) {
  2657. if ($mode == self::READ_REGEX) {
  2658. preg_match($expect, substr($this->interactiveBuffer, -1024), $matches);
  2659. $match = isset($matches[0]) ? $matches[0] : '';
  2660. }
  2661. $pos = strlen($match) ? strpos($this->interactiveBuffer, $match) : false;
  2662. if ($pos !== false) {
  2663. return $this->_string_shift($this->interactiveBuffer, $pos + strlen($match));
  2664. }
  2665. $response = $this->_get_channel_packet($channel);
  2666. if (is_bool($response)) {
  2667. $this->in_request_pty_exec = false;
  2668. return $response ? $this->_string_shift($this->interactiveBuffer, strlen($this->interactiveBuffer)) : false;
  2669. }
  2670. $this->interactiveBuffer.= $response;
  2671. }
  2672. }
  2673. /**
  2674. * Inputs a command into an interactive shell.
  2675. *
  2676. * @see self::read()
  2677. * @param string $cmd
  2678. * @return bool
  2679. * @access public
  2680. */
  2681. function write($cmd)
  2682. {
  2683. if (!$this->isAuthenticated()) {
  2684. user_error('Operation disallowed prior to login()');
  2685. return false;
  2686. }
  2687. if (!($this->bitmap & self::MASK_SHELL) && !$this->_initShell()) {
  2688. user_error('Unable to initiate an interactive shell session');
  2689. return false;
  2690. }
  2691. return $this->_send_channel_packet($this->_get_interactive_channel(), $cmd);
  2692. }
  2693. /**
  2694. * Start a subsystem.
  2695. *
  2696. * Right now only one subsystem at a time is supported. To support multiple subsystem's stopSubsystem() could accept
  2697. * a string that contained the name of the subsystem, but at that point, only one subsystem of each type could be opened.
  2698. * To support multiple subsystem's of the same name maybe it'd be best if startSubsystem() generated a new channel id and
  2699. * returns that and then that that was passed into stopSubsystem() but that'll be saved for a future date and implemented
  2700. * if there's sufficient demand for such a feature.
  2701. *
  2702. * @see self::stopSubsystem()
  2703. * @param string $subsystem
  2704. * @return bool
  2705. * @access public
  2706. */
  2707. function startSubsystem($subsystem)
  2708. {
  2709. $this->window_size_server_to_client[self::CHANNEL_SUBSYSTEM] = $this->window_size;
  2710. $packet = pack(
  2711. 'CNa*N3',
  2712. NET_SSH2_MSG_CHANNEL_OPEN,
  2713. strlen('session'),
  2714. 'session',
  2715. self::CHANNEL_SUBSYSTEM,
  2716. $this->window_size,
  2717. 0x4000
  2718. );
  2719. if (!$this->_send_binary_packet($packet)) {
  2720. return false;
  2721. }
  2722. $this->channel_status[self::CHANNEL_SUBSYSTEM] = NET_SSH2_MSG_CHANNEL_OPEN;
  2723. $response = $this->_get_channel_packet(self::CHANNEL_SUBSYSTEM);
  2724. if ($response === false) {
  2725. return false;
  2726. }
  2727. $packet = pack(
  2728. 'CNNa*CNa*',
  2729. NET_SSH2_MSG_CHANNEL_REQUEST,
  2730. $this->server_channels[self::CHANNEL_SUBSYSTEM],
  2731. strlen('subsystem'),
  2732. 'subsystem',
  2733. 1,
  2734. strlen($subsystem),
  2735. $subsystem
  2736. );
  2737. if (!$this->_send_binary_packet($packet)) {
  2738. return false;
  2739. }
  2740. $this->channel_status[self::CHANNEL_SUBSYSTEM] = NET_SSH2_MSG_CHANNEL_REQUEST;
  2741. $response = $this->_get_channel_packet(self::CHANNEL_SUBSYSTEM);
  2742. if ($response === false) {
  2743. return false;
  2744. }
  2745. $this->channel_status[self::CHANNEL_SUBSYSTEM] = NET_SSH2_MSG_CHANNEL_DATA;
  2746. $this->bitmap |= self::MASK_SHELL;
  2747. $this->in_subsystem = true;
  2748. return true;
  2749. }
  2750. /**
  2751. * Stops a subsystem.
  2752. *
  2753. * @see self::startSubsystem()
  2754. * @return bool
  2755. * @access public
  2756. */
  2757. function stopSubsystem()
  2758. {
  2759. $this->in_subsystem = false;
  2760. $this->_close_channel(self::CHANNEL_SUBSYSTEM);
  2761. return true;
  2762. }
  2763. /**
  2764. * Closes a channel
  2765. *
  2766. * If read() timed out you might want to just close the channel and have it auto-restart on the next read() call
  2767. *
  2768. * @access public
  2769. */
  2770. function reset()
  2771. {
  2772. $this->_close_channel($this->_get_interactive_channel());
  2773. }
  2774. /**
  2775. * Is timeout?
  2776. *
  2777. * Did exec() or read() return because they timed out or because they encountered the end?
  2778. *
  2779. * @access public
  2780. */
  2781. function isTimeout()
  2782. {
  2783. return $this->is_timeout;
  2784. }
  2785. /**
  2786. * Disconnect
  2787. *
  2788. * @access public
  2789. */
  2790. function disconnect()
  2791. {
  2792. $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
  2793. if (isset($this->realtime_log_file) && is_resource($this->realtime_log_file)) {
  2794. fclose($this->realtime_log_file);
  2795. }
  2796. }
  2797. /**
  2798. * Destructor.
  2799. *
  2800. * Will be called, automatically, if you're supporting just PHP5. If you're supporting PHP4, you'll need to call
  2801. * disconnect().
  2802. *
  2803. * @access public
  2804. */
  2805. function __destruct()
  2806. {
  2807. $this->disconnect();
  2808. }
  2809. /**
  2810. * Is the connection still active?
  2811. *
  2812. * @return bool
  2813. * @access public
  2814. */
  2815. function isConnected()
  2816. {
  2817. return (bool) ($this->bitmap & self::MASK_CONNECTED);
  2818. }
  2819. /**
  2820. * Have you successfully been logged in?
  2821. *
  2822. * @return bool
  2823. * @access public
  2824. */
  2825. function isAuthenticated()
  2826. {
  2827. return (bool) ($this->bitmap & self::MASK_LOGIN);
  2828. }
  2829. /**
  2830. * Resets a connection for re-use
  2831. *
  2832. * @param int $reason
  2833. * @access private
  2834. */
  2835. function _reset_connection($reason)
  2836. {
  2837. $this->_disconnect($reason);
  2838. $this->decrypt = $this->encrypt = false;
  2839. $this->decrypt_block_size = $this->encrypt_block_size = 8;
  2840. $this->hmac_check = $this->hmac_create = false;
  2841. $this->hmac_size = false;
  2842. $this->session_id = false;
  2843. $this->retry_connect = true;
  2844. $this->get_seq_no = $this->send_seq_no = 0;
  2845. }
  2846. /**
  2847. * Gets Binary Packets
  2848. *
  2849. * See '6. Binary Packet Protocol' of rfc4253 for more info.
  2850. *
  2851. * @see self::_send_binary_packet()
  2852. * @return string
  2853. * @access private
  2854. */
  2855. function _get_binary_packet($skip_channel_filter = false)
  2856. {
  2857. if (!is_resource($this->fsock) || feof($this->fsock)) {
  2858. user_error('Connection closed prematurely');
  2859. $this->bitmap = 0;
  2860. return false;
  2861. }
  2862. $start = microtime(true);
  2863. $raw = stream_get_contents($this->fsock, $this->decrypt_block_size);
  2864. if (!strlen($raw)) {
  2865. return '';
  2866. }
  2867. if ($this->decrypt !== false) {
  2868. $raw = $this->decrypt->decrypt($raw);
  2869. }
  2870. if ($raw === false) {
  2871. user_error('Unable to decrypt content');
  2872. return false;
  2873. }
  2874. if (strlen($raw) < 5) {
  2875. return false;
  2876. }
  2877. extract(unpack('Npacket_length/Cpadding_length', $this->_string_shift($raw, 5)));
  2878. $remaining_length = $packet_length + 4 - $this->decrypt_block_size;
  2879. // quoting <http://tools.ietf.org/html/rfc4253#section-6.1>,
  2880. // "implementations SHOULD check that the packet length is reasonable"
  2881. // PuTTY uses 0x9000 as the actual max packet size and so to shall we
  2882. if ($remaining_length < -$this->decrypt_block_size || $remaining_length > 0x9000 || $remaining_length % $this->decrypt_block_size != 0) {
  2883. if (!$this->bad_key_size_fix && $this->_bad_algorithm_candidate($this->decrypt_algorithm) && !($this->bitmap & SSH2::MASK_LOGIN)) {
  2884. $this->bad_key_size_fix = true;
  2885. $this->_reset_connection(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  2886. return false;
  2887. }
  2888. user_error('Invalid size');
  2889. return false;
  2890. }
  2891. $buffer = '';
  2892. while ($remaining_length > 0) {
  2893. $temp = stream_get_contents($this->fsock, $remaining_length);
  2894. if ($temp === false || feof($this->fsock)) {
  2895. user_error('Error reading from socket');
  2896. $this->bitmap = 0;
  2897. return false;
  2898. }
  2899. $buffer.= $temp;
  2900. $remaining_length-= strlen($temp);
  2901. }
  2902. $stop = microtime(true);
  2903. if (strlen($buffer)) {
  2904. $raw.= $this->decrypt !== false ? $this->decrypt->decrypt($buffer) : $buffer;
  2905. }
  2906. $payload = $this->_string_shift($raw, $packet_length - $padding_length - 1);
  2907. $padding = $this->_string_shift($raw, $padding_length); // should leave $raw empty
  2908. if ($this->hmac_check !== false) {
  2909. $hmac = stream_get_contents($this->fsock, $this->hmac_size);
  2910. if ($hmac === false || strlen($hmac) != $this->hmac_size) {
  2911. user_error('Error reading socket');
  2912. $this->bitmap = 0;
  2913. return false;
  2914. } elseif ($hmac != $this->hmac_check->hash(pack('NNCa*', $this->get_seq_no, $packet_length, $padding_length, $payload . $padding))) {
  2915. user_error('Invalid HMAC');
  2916. return false;
  2917. }
  2918. }
  2919. //if ($this->decompress) {
  2920. // $payload = gzinflate(substr($payload, 2));
  2921. //}
  2922. $this->get_seq_no++;
  2923. if (defined('NET_SSH2_LOGGING')) {
  2924. $current = microtime(true);
  2925. $message_number = isset($this->message_numbers[ord($payload[0])]) ? $this->message_numbers[ord($payload[0])] : 'UNKNOWN (' . ord($payload[0]) . ')';
  2926. $message_number = '<- ' . $message_number .
  2927. ' (since last: ' . round($current - $this->last_packet, 4) . ', network: ' . round($stop - $start, 4) . 's)';
  2928. $this->_append_log($message_number, $payload);
  2929. $this->last_packet = $current;
  2930. }
  2931. return $this->_filter($payload, $skip_channel_filter);
  2932. }
  2933. /**
  2934. * Filter Binary Packets
  2935. *
  2936. * Because some binary packets need to be ignored...
  2937. *
  2938. * @see self::_get_binary_packet()
  2939. * @return string
  2940. * @access private
  2941. */
  2942. function _filter($payload, $skip_channel_filter)
  2943. {
  2944. switch (ord($payload[0])) {
  2945. case NET_SSH2_MSG_DISCONNECT:
  2946. $this->_string_shift($payload, 1);
  2947. if (strlen($payload) < 8) {
  2948. return false;
  2949. }
  2950. extract(unpack('Nreason_code/Nlength', $this->_string_shift($payload, 8)));
  2951. $this->errors[] = 'SSH_MSG_DISCONNECT: ' . $this->disconnect_reasons[$reason_code] . "\r\n" . utf8_decode($this->_string_shift($payload, $length));
  2952. $this->bitmap = 0;
  2953. return false;
  2954. case NET_SSH2_MSG_IGNORE:
  2955. $payload = $this->_get_binary_packet($skip_channel_filter);
  2956. break;
  2957. case NET_SSH2_MSG_DEBUG:
  2958. $this->_string_shift($payload, 2);
  2959. if (strlen($payload) < 4) {
  2960. return false;
  2961. }
  2962. extract(unpack('Nlength', $this->_string_shift($payload, 4)));
  2963. $this->errors[] = 'SSH_MSG_DEBUG: ' . utf8_decode($this->_string_shift($payload, $length));
  2964. $payload = $this->_get_binary_packet($skip_channel_filter);
  2965. break;
  2966. case NET_SSH2_MSG_UNIMPLEMENTED:
  2967. return false;
  2968. case NET_SSH2_MSG_KEXINIT:
  2969. if ($this->session_id !== false) {
  2970. $this->send_kex_first = false;
  2971. if (!$this->_key_exchange($payload)) {
  2972. $this->bitmap = 0;
  2973. return false;
  2974. }
  2975. $payload = $this->_get_binary_packet($skip_channel_filter);
  2976. }
  2977. }
  2978. // see http://tools.ietf.org/html/rfc4252#section-5.4; only called when the encryption has been activated and when we haven't already logged in
  2979. if (($this->bitmap & self::MASK_CONNECTED) && !$this->isAuthenticated() && ord($payload[0]) == NET_SSH2_MSG_USERAUTH_BANNER) {
  2980. $this->_string_shift($payload, 1);
  2981. if (strlen($payload) < 4) {
  2982. return false;
  2983. }
  2984. extract(unpack('Nlength', $this->_string_shift($payload, 4)));
  2985. $this->banner_message = utf8_decode($this->_string_shift($payload, $length));
  2986. $payload = $this->_get_binary_packet();
  2987. }
  2988. // only called when we've already logged in
  2989. if (($this->bitmap & self::MASK_CONNECTED) && $this->isAuthenticated()) {
  2990. switch (ord($payload[0])) {
  2991. case NET_SSH2_MSG_CHANNEL_DATA:
  2992. case NET_SSH2_MSG_CHANNEL_EXTENDED_DATA:
  2993. case NET_SSH2_MSG_CHANNEL_REQUEST:
  2994. case NET_SSH2_MSG_CHANNEL_CLOSE:
  2995. case NET_SSH2_MSG_CHANNEL_EOF:
  2996. if (!$skip_channel_filter && !empty($this->server_channels)) {
  2997. $this->binary_packet_buffer = $payload;
  2998. $this->_get_channel_packet(true);
  2999. $payload = $this->_get_binary_packet();
  3000. }
  3001. break;
  3002. case NET_SSH2_MSG_GLOBAL_REQUEST: // see http://tools.ietf.org/html/rfc4254#section-4
  3003. if (strlen($payload) < 4) {
  3004. return false;
  3005. }
  3006. extract(unpack('Nlength', $this->_string_shift($payload, 4)));
  3007. $this->errors[] = 'SSH_MSG_GLOBAL_REQUEST: ' . $this->_string_shift($payload, $length);
  3008. if (!$this->_send_binary_packet(pack('C', NET_SSH2_MSG_REQUEST_FAILURE))) {
  3009. return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
  3010. }
  3011. $payload = $this->_get_binary_packet($skip_channel_filter);
  3012. break;
  3013. case NET_SSH2_MSG_CHANNEL_OPEN: // see http://tools.ietf.org/html/rfc4254#section-5.1
  3014. $this->_string_shift($payload, 1);
  3015. if (strlen($payload) < 4) {
  3016. return false;
  3017. }
  3018. extract(unpack('Nlength', $this->_string_shift($payload, 4)));
  3019. $data = $this->_string_shift($payload, $length);
  3020. if (strlen($payload) < 4) {
  3021. return false;
  3022. }
  3023. extract(unpack('Nserver_channel', $this->_string_shift($payload, 4)));
  3024. switch ($data) {
  3025. case 'auth-agent':
  3026. case 'auth-agent@openssh.com':
  3027. if (isset($this->agent)) {
  3028. $new_channel = self::CHANNEL_AGENT_FORWARD;
  3029. if (strlen($payload) < 8) {
  3030. return false;
  3031. }
  3032. extract(unpack('Nremote_window_size', $this->_string_shift($payload, 4)));
  3033. extract(unpack('Nremote_maximum_packet_size', $this->_string_shift($payload, 4)));
  3034. $this->packet_size_client_to_server[$new_channel] = $remote_window_size;
  3035. $this->window_size_server_to_client[$new_channel] = $remote_maximum_packet_size;
  3036. $this->window_size_client_to_server[$new_channel] = $this->window_size;
  3037. $packet_size = 0x4000;
  3038. $packet = pack(
  3039. 'CN4',
  3040. NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION,
  3041. $server_channel,
  3042. $new_channel,
  3043. $packet_size,
  3044. $packet_size
  3045. );
  3046. $this->server_channels[$new_channel] = $server_channel;
  3047. $this->channel_status[$new_channel] = NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION;
  3048. if (!$this->_send_binary_packet($packet)) {
  3049. return false;
  3050. }
  3051. }
  3052. break;
  3053. default:
  3054. $packet = pack(
  3055. 'CN3a*Na*',
  3056. NET_SSH2_MSG_REQUEST_FAILURE,
  3057. $server_channel,
  3058. NET_SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED,
  3059. 0,
  3060. '',
  3061. 0,
  3062. ''
  3063. );
  3064. if (!$this->_send_binary_packet($packet)) {
  3065. return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
  3066. }
  3067. }
  3068. $payload = $this->_get_binary_packet($skip_channel_filter);
  3069. break;
  3070. case NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST:
  3071. $this->_string_shift($payload, 1);
  3072. if (strlen($payload) < 8) {
  3073. return false;
  3074. }
  3075. extract(unpack('Nchannel', $this->_string_shift($payload, 4)));
  3076. extract(unpack('Nwindow_size', $this->_string_shift($payload, 4)));
  3077. $this->window_size_client_to_server[$channel]+= $window_size;
  3078. $payload = ($this->bitmap & self::MASK_WINDOW_ADJUST) ? true : $this->_get_binary_packet($skip_channel_filter);
  3079. }
  3080. }
  3081. return $payload;
  3082. }
  3083. /**
  3084. * Enable Quiet Mode
  3085. *
  3086. * Suppress stderr from output
  3087. *
  3088. * @access public
  3089. */
  3090. function enableQuietMode()
  3091. {
  3092. $this->quiet_mode = true;
  3093. }
  3094. /**
  3095. * Disable Quiet Mode
  3096. *
  3097. * Show stderr in output
  3098. *
  3099. * @access public
  3100. */
  3101. function disableQuietMode()
  3102. {
  3103. $this->quiet_mode = false;
  3104. }
  3105. /**
  3106. * Returns whether Quiet Mode is enabled or not
  3107. *
  3108. * @see self::enableQuietMode()
  3109. * @see self::disableQuietMode()
  3110. * @access public
  3111. * @return bool
  3112. */
  3113. function isQuietModeEnabled()
  3114. {
  3115. return $this->quiet_mode;
  3116. }
  3117. /**
  3118. * Enable request-pty when using exec()
  3119. *
  3120. * @access public
  3121. */
  3122. function enablePTY()
  3123. {
  3124. $this->request_pty = true;
  3125. }
  3126. /**
  3127. * Disable request-pty when using exec()
  3128. *
  3129. * @access public
  3130. */
  3131. function disablePTY()
  3132. {
  3133. if ($this->in_request_pty_exec) {
  3134. $this->_close_channel(self::CHANNEL_EXEC);
  3135. $this->in_request_pty_exec = false;
  3136. }
  3137. $this->request_pty = false;
  3138. }
  3139. /**
  3140. * Returns whether request-pty is enabled or not
  3141. *
  3142. * @see self::enablePTY()
  3143. * @see self::disablePTY()
  3144. * @access public
  3145. * @return bool
  3146. */
  3147. function isPTYEnabled()
  3148. {
  3149. return $this->request_pty;
  3150. }
  3151. /**
  3152. * Gets channel data
  3153. *
  3154. * Returns the data as a string if it's available and false if not.
  3155. *
  3156. * @param $client_channel
  3157. * @return mixed
  3158. * @access private
  3159. */
  3160. function _get_channel_packet($client_channel, $skip_extended = false)
  3161. {
  3162. if (!empty($this->channel_buffers[$client_channel])) {
  3163. return array_shift($this->channel_buffers[$client_channel]);
  3164. }
  3165. while (true) {
  3166. if ($this->binary_packet_buffer !== false) {
  3167. $response = $this->binary_packet_buffer;
  3168. $this->binary_packet_buffer = false;
  3169. } else {
  3170. if ($this->curTimeout) {
  3171. if ($this->curTimeout < 0) {
  3172. $this->is_timeout = true;
  3173. return true;
  3174. }
  3175. $read = array($this->fsock);
  3176. $write = $except = null;
  3177. $start = microtime(true);
  3178. $sec = floor($this->curTimeout);
  3179. $usec = 1000000 * ($this->curTimeout - $sec);
  3180. // on windows this returns a "Warning: Invalid CRT parameters detected" error
  3181. if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) {
  3182. $this->is_timeout = true;
  3183. return true;
  3184. }
  3185. $elapsed = microtime(true) - $start;
  3186. $this->curTimeout-= $elapsed;
  3187. }
  3188. $response = $this->_get_binary_packet(true);
  3189. if ($response === false) {
  3190. user_error('Connection closed by server');
  3191. return false;
  3192. }
  3193. }
  3194. if ($client_channel == -1 && $response === true) {
  3195. return true;
  3196. }
  3197. if (!strlen($response)) {
  3198. return '';
  3199. }
  3200. if (!strlen($response)) {
  3201. return false;
  3202. }
  3203. extract(unpack('Ctype', $this->_string_shift($response, 1)));
  3204. if (strlen($response) < 4) {
  3205. return false;
  3206. }
  3207. if ($type == NET_SSH2_MSG_CHANNEL_OPEN) {
  3208. extract(unpack('Nlength', $this->_string_shift($response, 4)));
  3209. } else {
  3210. extract(unpack('Nchannel', $this->_string_shift($response, 4)));
  3211. }
  3212. // will not be setup yet on incoming channel open request
  3213. if (isset($channel) && isset($this->channel_status[$channel]) && isset($this->window_size_server_to_client[$channel])) {
  3214. $this->window_size_server_to_client[$channel]-= strlen($response);
  3215. // resize the window, if appropriate
  3216. if ($this->window_size_server_to_client[$channel] < 0) {
  3217. $packet = pack('CNN', NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST, $this->server_channels[$channel], $this->window_size);
  3218. if (!$this->_send_binary_packet($packet)) {
  3219. return false;
  3220. }
  3221. $this->window_size_server_to_client[$channel]+= $this->window_size;
  3222. }
  3223. switch ($type) {
  3224. case NET_SSH2_MSG_CHANNEL_EXTENDED_DATA:
  3225. /*
  3226. if ($client_channel == NET_SSH2_CHANNEL_EXEC) {
  3227. $this->_send_channel_packet($client_channel, chr(0));
  3228. }
  3229. */
  3230. // currently, there's only one possible value for $data_type_code: NET_SSH2_EXTENDED_DATA_STDERR
  3231. if (strlen($response) < 8) {
  3232. return false;
  3233. }
  3234. extract(unpack('Ndata_type_code/Nlength', $this->_string_shift($response, 8)));
  3235. $data = $this->_string_shift($response, $length);
  3236. $this->stdErrorLog.= $data;
  3237. if ($skip_extended || $this->quiet_mode) {
  3238. continue 2;
  3239. }
  3240. if ($client_channel == $channel && $this->channel_status[$channel] == NET_SSH2_MSG_CHANNEL_DATA) {
  3241. return $data;
  3242. }
  3243. if (!isset($this->channel_buffers[$channel])) {
  3244. $this->channel_buffers[$channel] = array();
  3245. }
  3246. $this->channel_buffers[$channel][] = $data;
  3247. continue 2;
  3248. case NET_SSH2_MSG_CHANNEL_REQUEST:
  3249. if ($this->channel_status[$channel] == NET_SSH2_MSG_CHANNEL_CLOSE) {
  3250. continue 2;
  3251. }
  3252. if (strlen($response) < 4) {
  3253. return false;
  3254. }
  3255. extract(unpack('Nlength', $this->_string_shift($response, 4)));
  3256. $value = $this->_string_shift($response, $length);
  3257. switch ($value) {
  3258. case 'exit-signal':
  3259. $this->_string_shift($response, 1);
  3260. if (strlen($response) < 4) {
  3261. return false;
  3262. }
  3263. extract(unpack('Nlength', $this->_string_shift($response, 4)));
  3264. $this->errors[] = 'SSH_MSG_CHANNEL_REQUEST (exit-signal): ' . $this->_string_shift($response, $length);
  3265. $this->_string_shift($response, 1);
  3266. if (strlen($response) < 4) {
  3267. return false;
  3268. }
  3269. extract(unpack('Nlength', $this->_string_shift($response, 4)));
  3270. if ($length) {
  3271. $this->errors[count($this->errors)].= "\r\n" . $this->_string_shift($response, $length);
  3272. }
  3273. $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_EOF, $this->server_channels[$client_channel]));
  3274. $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$channel]));
  3275. $this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_EOF;
  3276. continue 3;
  3277. case 'exit-status':
  3278. if (strlen($response) < 5) {
  3279. return false;
  3280. }
  3281. extract(unpack('Cfalse/Nexit_status', $this->_string_shift($response, 5)));
  3282. $this->exit_status = $exit_status;
  3283. // "The client MAY ignore these messages."
  3284. // -- http://tools.ietf.org/html/rfc4254#section-6.10
  3285. continue 3;
  3286. default:
  3287. // "Some systems may not implement signals, in which case they SHOULD ignore this message."
  3288. // -- http://tools.ietf.org/html/rfc4254#section-6.9
  3289. continue 3;
  3290. }
  3291. }
  3292. switch ($this->channel_status[$channel]) {
  3293. case NET_SSH2_MSG_CHANNEL_OPEN:
  3294. switch ($type) {
  3295. case NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION:
  3296. if (strlen($response) < 4) {
  3297. return false;
  3298. }
  3299. extract(unpack('Nserver_channel', $this->_string_shift($response, 4)));
  3300. $this->server_channels[$channel] = $server_channel;
  3301. if (strlen($response) < 4) {
  3302. return false;
  3303. }
  3304. extract(unpack('Nwindow_size', $this->_string_shift($response, 4)));
  3305. if ($window_size < 0) {
  3306. $window_size&= 0x7FFFFFFF;
  3307. $window_size+= 0x80000000;
  3308. }
  3309. $this->window_size_client_to_server[$channel] = $window_size;
  3310. if (strlen($response) < 4) {
  3311. return false;
  3312. }
  3313. $temp = unpack('Npacket_size_client_to_server', $this->_string_shift($response, 4));
  3314. $this->packet_size_client_to_server[$channel] = $temp['packet_size_client_to_server'];
  3315. $result = $client_channel == $channel ? true : $this->_get_channel_packet($client_channel, $skip_extended);
  3316. $this->_on_channel_open();
  3317. return $result;
  3318. //case NET_SSH2_MSG_CHANNEL_OPEN_FAILURE:
  3319. default:
  3320. user_error('Unable to open channel');
  3321. return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
  3322. }
  3323. break;
  3324. case NET_SSH2_MSG_CHANNEL_REQUEST:
  3325. switch ($type) {
  3326. case NET_SSH2_MSG_CHANNEL_SUCCESS:
  3327. return true;
  3328. case NET_SSH2_MSG_CHANNEL_FAILURE:
  3329. return false;
  3330. default:
  3331. user_error('Unable to fulfill channel request');
  3332. return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
  3333. }
  3334. case NET_SSH2_MSG_CHANNEL_CLOSE:
  3335. return $type == NET_SSH2_MSG_CHANNEL_CLOSE ? true : $this->_get_channel_packet($client_channel, $skip_extended);
  3336. }
  3337. }
  3338. // ie. $this->channel_status[$channel] == NET_SSH2_MSG_CHANNEL_DATA
  3339. switch ($type) {
  3340. case NET_SSH2_MSG_CHANNEL_DATA:
  3341. /*
  3342. if ($channel == self::CHANNEL_EXEC) {
  3343. // SCP requires null packets, such as this, be sent. further, in the case of the ssh.com SSH server
  3344. // this actually seems to make things twice as fast. more to the point, the message right after
  3345. // SSH_MSG_CHANNEL_DATA (usually SSH_MSG_IGNORE) won't block for as long as it would have otherwise.
  3346. // in OpenSSH it slows things down but only by a couple thousandths of a second.
  3347. $this->_send_channel_packet($channel, chr(0));
  3348. }
  3349. */
  3350. if (strlen($response) < 4) {
  3351. return false;
  3352. }
  3353. extract(unpack('Nlength', $this->_string_shift($response, 4)));
  3354. $data = $this->_string_shift($response, $length);
  3355. if ($channel == self::CHANNEL_AGENT_FORWARD) {
  3356. $agent_response = $this->agent->_forward_data($data);
  3357. if (!is_bool($agent_response)) {
  3358. $this->_send_channel_packet($channel, $agent_response);
  3359. }
  3360. break;
  3361. }
  3362. if ($client_channel == $channel) {
  3363. return $data;
  3364. }
  3365. if (!isset($this->channel_buffers[$channel])) {
  3366. $this->channel_buffers[$channel] = array();
  3367. }
  3368. $this->channel_buffers[$channel][] = $data;
  3369. break;
  3370. case NET_SSH2_MSG_CHANNEL_CLOSE:
  3371. $this->curTimeout = 0;
  3372. if ($this->bitmap & self::MASK_SHELL) {
  3373. $this->bitmap&= ~self::MASK_SHELL;
  3374. }
  3375. if ($this->channel_status[$channel] != NET_SSH2_MSG_CHANNEL_EOF) {
  3376. $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$channel]));
  3377. }
  3378. $this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_CLOSE;
  3379. if ($client_channel == $channel) {
  3380. return true;
  3381. }
  3382. case NET_SSH2_MSG_CHANNEL_EOF:
  3383. break;
  3384. default:
  3385. user_error('Error reading channel data');
  3386. return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
  3387. }
  3388. }
  3389. }
  3390. /**
  3391. * Sends Binary Packets
  3392. *
  3393. * See '6. Binary Packet Protocol' of rfc4253 for more info.
  3394. *
  3395. * @param string $data
  3396. * @param string $logged
  3397. * @see self::_get_binary_packet()
  3398. * @return bool
  3399. * @access private
  3400. */
  3401. function _send_binary_packet($data, $logged = null)
  3402. {
  3403. if (!is_resource($this->fsock) || feof($this->fsock)) {
  3404. user_error('Connection closed prematurely');
  3405. $this->bitmap = 0;
  3406. return false;
  3407. }
  3408. //if ($this->compress) {
  3409. // // the -4 removes the checksum:
  3410. // // http://php.net/function.gzcompress#57710
  3411. // $data = substr(gzcompress($data), 0, -4);
  3412. //}
  3413. // 4 (packet length) + 1 (padding length) + 4 (minimal padding amount) == 9
  3414. $packet_length = strlen($data) + 9;
  3415. // round up to the nearest $this->encrypt_block_size
  3416. $packet_length+= (($this->encrypt_block_size - 1) * $packet_length) % $this->encrypt_block_size;
  3417. // subtracting strlen($data) is obvious - subtracting 5 is necessary because of packet_length and padding_length
  3418. $padding_length = $packet_length - strlen($data) - 5;
  3419. $padding = Random::string($padding_length);
  3420. // we subtract 4 from packet_length because the packet_length field isn't supposed to include itself
  3421. $packet = pack('NCa*', $packet_length - 4, $padding_length, $data . $padding);
  3422. $hmac = $this->hmac_create !== false ? $this->hmac_create->hash(pack('Na*', $this->send_seq_no, $packet)) : '';
  3423. $this->send_seq_no++;
  3424. if ($this->encrypt !== false) {
  3425. $packet = $this->encrypt->encrypt($packet);
  3426. }
  3427. $packet.= $hmac;
  3428. $start = microtime(true);
  3429. $result = strlen($packet) == fputs($this->fsock, $packet);
  3430. $stop = microtime(true);
  3431. if (defined('NET_SSH2_LOGGING')) {
  3432. $current = microtime(true);
  3433. $message_number = isset($this->message_numbers[ord($data[0])]) ? $this->message_numbers[ord($data[0])] : 'UNKNOWN (' . ord($data[0]) . ')';
  3434. $message_number = '-> ' . $message_number .
  3435. ' (since last: ' . round($current - $this->last_packet, 4) . ', network: ' . round($stop - $start, 4) . 's)';
  3436. $this->_append_log($message_number, isset($logged) ? $logged : $data);
  3437. $this->last_packet = $current;
  3438. }
  3439. return $result;
  3440. }
  3441. /**
  3442. * Logs data packets
  3443. *
  3444. * Makes sure that only the last 1MB worth of packets will be logged
  3445. *
  3446. * @param string $data
  3447. * @access private
  3448. */
  3449. function _append_log($message_number, $message)
  3450. {
  3451. // remove the byte identifying the message type from all but the first two messages (ie. the identification strings)
  3452. if (strlen($message_number) > 2) {
  3453. $this->_string_shift($message);
  3454. }
  3455. switch (NET_SSH2_LOGGING) {
  3456. // useful for benchmarks
  3457. case self::LOG_SIMPLE:
  3458. $this->message_number_log[] = $message_number;
  3459. break;
  3460. // the most useful log for SSH2
  3461. case self::LOG_COMPLEX:
  3462. $this->message_number_log[] = $message_number;
  3463. $this->log_size+= strlen($message);
  3464. $this->message_log[] = $message;
  3465. while ($this->log_size > self::LOG_MAX_SIZE) {
  3466. $this->log_size-= strlen(array_shift($this->message_log));
  3467. array_shift($this->message_number_log);
  3468. }
  3469. break;
  3470. // dump the output out realtime; packets may be interspersed with non packets,
  3471. // passwords won't be filtered out and select other packets may not be correctly
  3472. // identified
  3473. case self::LOG_REALTIME:
  3474. switch (PHP_SAPI) {
  3475. case 'cli':
  3476. $start = $stop = "\r\n";
  3477. break;
  3478. default:
  3479. $start = '<pre>';
  3480. $stop = '</pre>';
  3481. }
  3482. echo $start . $this->_format_log(array($message), array($message_number)) . $stop;
  3483. @flush();
  3484. @ob_flush();
  3485. break;
  3486. // basically the same thing as self::LOG_REALTIME with the caveat that self::LOG_REALTIME_FILE
  3487. // needs to be defined and that the resultant log file will be capped out at self::LOG_MAX_SIZE.
  3488. // the earliest part of the log file is denoted by the first <<< START >>> and is not going to necessarily
  3489. // at the beginning of the file
  3490. case self::LOG_REALTIME_FILE:
  3491. if (!isset($this->realtime_log_file)) {
  3492. // PHP doesn't seem to like using constants in fopen()
  3493. $filename = self::LOG_REALTIME_FILENAME;
  3494. $fp = fopen($filename, 'w');
  3495. $this->realtime_log_file = $fp;
  3496. }
  3497. if (!is_resource($this->realtime_log_file)) {
  3498. break;
  3499. }
  3500. $entry = $this->_format_log(array($message), array($message_number));
  3501. if ($this->realtime_log_wrap) {
  3502. $temp = "<<< START >>>\r\n";
  3503. $entry.= $temp;
  3504. fseek($this->realtime_log_file, ftell($this->realtime_log_file) - strlen($temp));
  3505. }
  3506. $this->realtime_log_size+= strlen($entry);
  3507. if ($this->realtime_log_size > self::LOG_MAX_SIZE) {
  3508. fseek($this->realtime_log_file, 0);
  3509. $this->realtime_log_size = strlen($entry);
  3510. $this->realtime_log_wrap = true;
  3511. }
  3512. fputs($this->realtime_log_file, $entry);
  3513. }
  3514. }
  3515. /**
  3516. * Sends channel data
  3517. *
  3518. * Spans multiple SSH_MSG_CHANNEL_DATAs if appropriate
  3519. *
  3520. * @param int $client_channel
  3521. * @param string $data
  3522. * @return bool
  3523. * @access private
  3524. */
  3525. function _send_channel_packet($client_channel, $data)
  3526. {
  3527. while (strlen($data)) {
  3528. if (!$this->window_size_client_to_server[$client_channel]) {
  3529. $this->bitmap^= self::MASK_WINDOW_ADJUST;
  3530. // using an invalid channel will let the buffers be built up for the valid channels
  3531. $this->_get_channel_packet(-1);
  3532. $this->bitmap^= self::MASK_WINDOW_ADJUST;
  3533. }
  3534. /* The maximum amount of data allowed is determined by the maximum
  3535. packet size for the channel, and the current window size, whichever
  3536. is smaller.
  3537. -- http://tools.ietf.org/html/rfc4254#section-5.2 */
  3538. $max_size = min(
  3539. $this->packet_size_client_to_server[$client_channel],
  3540. $this->window_size_client_to_server[$client_channel]
  3541. );
  3542. $temp = $this->_string_shift($data, $max_size);
  3543. $packet = pack(
  3544. 'CN2a*',
  3545. NET_SSH2_MSG_CHANNEL_DATA,
  3546. $this->server_channels[$client_channel],
  3547. strlen($temp),
  3548. $temp
  3549. );
  3550. $this->window_size_client_to_server[$client_channel]-= strlen($temp);
  3551. if (!$this->_send_binary_packet($packet)) {
  3552. return false;
  3553. }
  3554. }
  3555. return true;
  3556. }
  3557. /**
  3558. * Closes and flushes a channel
  3559. *
  3560. * \phpseclib\Net\SSH2 doesn't properly close most channels. For exec() channels are normally closed by the server
  3561. * and for SFTP channels are presumably closed when the client disconnects. This functions is intended
  3562. * for SCP more than anything.
  3563. *
  3564. * @param int $client_channel
  3565. * @param bool $want_reply
  3566. * @return bool
  3567. * @access private
  3568. */
  3569. function _close_channel($client_channel, $want_reply = false)
  3570. {
  3571. // see http://tools.ietf.org/html/rfc4254#section-5.3
  3572. $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_EOF, $this->server_channels[$client_channel]));
  3573. if (!$want_reply) {
  3574. $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$client_channel]));
  3575. }
  3576. $this->channel_status[$client_channel] = NET_SSH2_MSG_CHANNEL_CLOSE;
  3577. $this->curTimeout = 0;
  3578. while (!is_bool($this->_get_channel_packet($client_channel))) {
  3579. }
  3580. if ($want_reply) {
  3581. $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$client_channel]));
  3582. }
  3583. if ($this->bitmap & self::MASK_SHELL) {
  3584. $this->bitmap&= ~self::MASK_SHELL;
  3585. }
  3586. }
  3587. /**
  3588. * Disconnect
  3589. *
  3590. * @param int $reason
  3591. * @return bool
  3592. * @access private
  3593. */
  3594. function _disconnect($reason)
  3595. {
  3596. if ($this->bitmap & self::MASK_CONNECTED) {
  3597. $data = pack('CNNa*Na*', NET_SSH2_MSG_DISCONNECT, $reason, 0, '', 0, '');
  3598. $this->_send_binary_packet($data);
  3599. $this->bitmap = 0;
  3600. fclose($this->fsock);
  3601. return false;
  3602. }
  3603. }
  3604. /**
  3605. * String Shift
  3606. *
  3607. * Inspired by array_shift
  3608. *
  3609. * @param string $string
  3610. * @param int $index
  3611. * @return string
  3612. * @access private
  3613. */
  3614. function _string_shift(&$string, $index = 1)
  3615. {
  3616. $substr = substr($string, 0, $index);
  3617. $string = substr($string, $index);
  3618. return $substr;
  3619. }
  3620. /**
  3621. * Define Array
  3622. *
  3623. * Takes any number of arrays whose indices are integers and whose values are strings and defines a bunch of
  3624. * named constants from it, using the value as the name of the constant and the index as the value of the constant.
  3625. * If any of the constants that would be defined already exists, none of the constants will be defined.
  3626. *
  3627. * @param array $array
  3628. * @access private
  3629. */
  3630. function _define_array()
  3631. {
  3632. $args = func_get_args();
  3633. foreach ($args as $arg) {
  3634. foreach ($arg as $key => $value) {
  3635. if (!defined($value)) {
  3636. define($value, $key);
  3637. } else {
  3638. break 2;
  3639. }
  3640. }
  3641. }
  3642. }
  3643. /**
  3644. * Returns a log of the packets that have been sent and received.
  3645. *
  3646. * Returns a string if NET_SSH2_LOGGING == self::LOG_COMPLEX, an array if NET_SSH2_LOGGING == self::LOG_SIMPLE and false if !defined('NET_SSH2_LOGGING')
  3647. *
  3648. * @access public
  3649. * @return array|false|string
  3650. */
  3651. function getLog()
  3652. {
  3653. if (!defined('NET_SSH2_LOGGING')) {
  3654. return false;
  3655. }
  3656. switch (NET_SSH2_LOGGING) {
  3657. case self::LOG_SIMPLE:
  3658. return $this->message_number_log;
  3659. case self::LOG_COMPLEX:
  3660. $log = $this->_format_log($this->message_log, $this->message_number_log);
  3661. return PHP_SAPI == 'cli' ? $log : '<pre>' . $log . '</pre>';
  3662. default:
  3663. return false;
  3664. }
  3665. }
  3666. /**
  3667. * Formats a log for printing
  3668. *
  3669. * @param array $message_log
  3670. * @param array $message_number_log
  3671. * @access private
  3672. * @return string
  3673. */
  3674. function _format_log($message_log, $message_number_log)
  3675. {
  3676. $output = '';
  3677. for ($i = 0; $i < count($message_log); $i++) {
  3678. $output.= $message_number_log[$i] . "\r\n";
  3679. $current_log = $message_log[$i];
  3680. $j = 0;
  3681. do {
  3682. if (strlen($current_log)) {
  3683. $output.= str_pad(dechex($j), 7, '0', STR_PAD_LEFT) . '0 ';
  3684. }
  3685. $fragment = $this->_string_shift($current_log, $this->log_short_width);
  3686. $hex = substr(preg_replace_callback('#.#s', array($this, '_format_log_helper'), $fragment), strlen($this->log_boundary));
  3687. // replace non ASCII printable characters with dots
  3688. // http://en.wikipedia.org/wiki/ASCII#ASCII_printable_characters
  3689. // also replace < with a . since < messes up the output on web browsers
  3690. $raw = preg_replace('#[^\x20-\x7E]|<#', '.', $fragment);
  3691. $output.= str_pad($hex, $this->log_long_width - $this->log_short_width, ' ') . $raw . "\r\n";
  3692. $j++;
  3693. } while (strlen($current_log));
  3694. $output.= "\r\n";
  3695. }
  3696. return $output;
  3697. }
  3698. /**
  3699. * Helper function for _format_log
  3700. *
  3701. * For use with preg_replace_callback()
  3702. *
  3703. * @param array $matches
  3704. * @access private
  3705. * @return string
  3706. */
  3707. function _format_log_helper($matches)
  3708. {
  3709. return $this->log_boundary . str_pad(dechex(ord($matches[0])), 2, '0', STR_PAD_LEFT);
  3710. }
  3711. /**
  3712. * Helper function for agent->_on_channel_open()
  3713. *
  3714. * Used when channels are created to inform agent
  3715. * of said channel opening. Must be called after
  3716. * channel open confirmation received
  3717. *
  3718. * @access private
  3719. */
  3720. function _on_channel_open()
  3721. {
  3722. if (isset($this->agent)) {
  3723. $this->agent->_on_channel_open($this);
  3724. }
  3725. }
  3726. /**
  3727. * Returns the first value of the intersection of two arrays or false if
  3728. * the intersection is empty. The order is defined by the first parameter.
  3729. *
  3730. * @param array $array1
  3731. * @param array $array2
  3732. * @return mixed False if intersection is empty, else intersected value.
  3733. * @access private
  3734. */
  3735. function _array_intersect_first($array1, $array2)
  3736. {
  3737. foreach ($array1 as $value) {
  3738. if (in_array($value, $array2)) {
  3739. return $value;
  3740. }
  3741. }
  3742. return false;
  3743. }
  3744. /**
  3745. * Returns all errors
  3746. *
  3747. * @return string[]
  3748. * @access public
  3749. */
  3750. function getErrors()
  3751. {
  3752. return $this->errors;
  3753. }
  3754. /**
  3755. * Returns the last error
  3756. *
  3757. * @return string
  3758. * @access public
  3759. */
  3760. function getLastError()
  3761. {
  3762. $count = count($this->errors);
  3763. if ($count > 0) {
  3764. return $this->errors[$count - 1];
  3765. }
  3766. }
  3767. /**
  3768. * Return the server identification.
  3769. *
  3770. * @return string
  3771. * @access public
  3772. */
  3773. function getServerIdentification()
  3774. {
  3775. $this->_connect();
  3776. return $this->server_identifier;
  3777. }
  3778. /**
  3779. * Return a list of the key exchange algorithms the server supports.
  3780. *
  3781. * @return array
  3782. * @access public
  3783. */
  3784. function getKexAlgorithms()
  3785. {
  3786. $this->_connect();
  3787. return $this->kex_algorithms;
  3788. }
  3789. /**
  3790. * Return a list of the host key (public key) algorithms the server supports.
  3791. *
  3792. * @return array
  3793. * @access public
  3794. */
  3795. function getServerHostKeyAlgorithms()
  3796. {
  3797. $this->_connect();
  3798. return $this->server_host_key_algorithms;
  3799. }
  3800. /**
  3801. * Return a list of the (symmetric key) encryption algorithms the server supports, when receiving stuff from the client.
  3802. *
  3803. * @return array
  3804. * @access public
  3805. */
  3806. function getEncryptionAlgorithmsClient2Server()
  3807. {
  3808. $this->_connect();
  3809. return $this->encryption_algorithms_client_to_server;
  3810. }
  3811. /**
  3812. * Return a list of the (symmetric key) encryption algorithms the server supports, when sending stuff to the client.
  3813. *
  3814. * @return array
  3815. * @access public
  3816. */
  3817. function getEncryptionAlgorithmsServer2Client()
  3818. {
  3819. $this->_connect();
  3820. return $this->encryption_algorithms_server_to_client;
  3821. }
  3822. /**
  3823. * Return a list of the MAC algorithms the server supports, when receiving stuff from the client.
  3824. *
  3825. * @return array
  3826. * @access public
  3827. */
  3828. function getMACAlgorithmsClient2Server()
  3829. {
  3830. $this->_connect();
  3831. return $this->mac_algorithms_client_to_server;
  3832. }
  3833. /**
  3834. * Return a list of the MAC algorithms the server supports, when sending stuff to the client.
  3835. *
  3836. * @return array
  3837. * @access public
  3838. */
  3839. function getMACAlgorithmsServer2Client()
  3840. {
  3841. $this->_connect();
  3842. return $this->mac_algorithms_server_to_client;
  3843. }
  3844. /**
  3845. * Return a list of the compression algorithms the server supports, when receiving stuff from the client.
  3846. *
  3847. * @return array
  3848. * @access public
  3849. */
  3850. function getCompressionAlgorithmsClient2Server()
  3851. {
  3852. $this->_connect();
  3853. return $this->compression_algorithms_client_to_server;
  3854. }
  3855. /**
  3856. * Return a list of the compression algorithms the server supports, when sending stuff to the client.
  3857. *
  3858. * @return array
  3859. * @access public
  3860. */
  3861. function getCompressionAlgorithmsServer2Client()
  3862. {
  3863. $this->_connect();
  3864. return $this->compression_algorithms_server_to_client;
  3865. }
  3866. /**
  3867. * Return a list of the languages the server supports, when sending stuff to the client.
  3868. *
  3869. * @return array
  3870. * @access public
  3871. */
  3872. function getLanguagesServer2Client()
  3873. {
  3874. $this->_connect();
  3875. return $this->languages_server_to_client;
  3876. }
  3877. /**
  3878. * Return a list of the languages the server supports, when receiving stuff from the client.
  3879. *
  3880. * @return array
  3881. * @access public
  3882. */
  3883. function getLanguagesClient2Server()
  3884. {
  3885. $this->_connect();
  3886. return $this->languages_client_to_server;
  3887. }
  3888. /**
  3889. * Returns the banner message.
  3890. *
  3891. * Quoting from the RFC, "in some jurisdictions, sending a warning message before
  3892. * authentication may be relevant for getting legal protection."
  3893. *
  3894. * @return string
  3895. * @access public
  3896. */
  3897. function getBannerMessage()
  3898. {
  3899. return $this->banner_message;
  3900. }
  3901. /**
  3902. * Returns the server public host key.
  3903. *
  3904. * Caching this the first time you connect to a server and checking the result on subsequent connections
  3905. * is recommended. Returns false if the server signature is not signed correctly with the public host key.
  3906. *
  3907. * @return mixed
  3908. * @access public
  3909. */
  3910. function getServerPublicHostKey()
  3911. {
  3912. if (!($this->bitmap & self::MASK_CONSTRUCTOR)) {
  3913. if (!$this->_connect()) {
  3914. return false;
  3915. }
  3916. }
  3917. $signature = $this->signature;
  3918. $server_public_host_key = $this->server_public_host_key;
  3919. if (strlen($server_public_host_key) < 4) {
  3920. return false;
  3921. }
  3922. extract(unpack('Nlength', $this->_string_shift($server_public_host_key, 4)));
  3923. $this->_string_shift($server_public_host_key, $length);
  3924. if ($this->signature_validated) {
  3925. return $this->bitmap ?
  3926. $this->signature_format . ' ' . base64_encode($this->server_public_host_key) :
  3927. false;
  3928. }
  3929. $this->signature_validated = true;
  3930. switch ($this->signature_format) {
  3931. case 'ssh-dss':
  3932. $zero = new BigInteger();
  3933. if (strlen($server_public_host_key) < 4) {
  3934. return false;
  3935. }
  3936. $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
  3937. $p = new BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
  3938. if (strlen($server_public_host_key) < 4) {
  3939. return false;
  3940. }
  3941. $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
  3942. $q = new BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
  3943. if (strlen($server_public_host_key) < 4) {
  3944. return false;
  3945. }
  3946. $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
  3947. $g = new BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
  3948. if (strlen($server_public_host_key) < 4) {
  3949. return false;
  3950. }
  3951. $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
  3952. $y = new BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
  3953. /* The value for 'dss_signature_blob' is encoded as a string containing
  3954. r, followed by s (which are 160-bit integers, without lengths or
  3955. padding, unsigned, and in network byte order). */
  3956. $temp = unpack('Nlength', $this->_string_shift($signature, 4));
  3957. if ($temp['length'] != 40) {
  3958. user_error('Invalid signature');
  3959. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  3960. }
  3961. $r = new BigInteger($this->_string_shift($signature, 20), 256);
  3962. $s = new BigInteger($this->_string_shift($signature, 20), 256);
  3963. switch (true) {
  3964. case $r->equals($zero):
  3965. case $r->compare($q) >= 0:
  3966. case $s->equals($zero):
  3967. case $s->compare($q) >= 0:
  3968. user_error('Invalid signature');
  3969. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  3970. }
  3971. $w = $s->modInverse($q);
  3972. $u1 = $w->multiply(new BigInteger(sha1($this->exchange_hash), 16));
  3973. list(, $u1) = $u1->divide($q);
  3974. $u2 = $w->multiply($r);
  3975. list(, $u2) = $u2->divide($q);
  3976. $g = $g->modPow($u1, $p);
  3977. $y = $y->modPow($u2, $p);
  3978. $v = $g->multiply($y);
  3979. list(, $v) = $v->divide($p);
  3980. list(, $v) = $v->divide($q);
  3981. if (!$v->equals($r)) {
  3982. user_error('Bad server signature');
  3983. return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
  3984. }
  3985. break;
  3986. case 'ssh-rsa':
  3987. if (strlen($server_public_host_key) < 4) {
  3988. return false;
  3989. }
  3990. $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
  3991. $e = new BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
  3992. if (strlen($server_public_host_key) < 4) {
  3993. return false;
  3994. }
  3995. $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
  3996. $rawN = $this->_string_shift($server_public_host_key, $temp['length']);
  3997. $n = new BigInteger($rawN, -256);
  3998. $nLength = strlen(ltrim($rawN, "\0"));
  3999. /*
  4000. if (strlen($signature) < 4) {
  4001. return false;
  4002. }
  4003. $temp = unpack('Nlength', $this->_string_shift($signature, 4));
  4004. $signature = $this->_string_shift($signature, $temp['length']);
  4005. $rsa = new RSA();
  4006. $rsa->setSignatureMode(RSA::SIGNATURE_PKCS1);
  4007. $rsa->loadKey(array('e' => $e, 'n' => $n), RSA::PUBLIC_FORMAT_RAW);
  4008. if (!$rsa->verify($this->exchange_hash, $signature)) {
  4009. user_error('Bad server signature');
  4010. return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
  4011. }
  4012. */
  4013. if (strlen($signature) < 4) {
  4014. return false;
  4015. }
  4016. $temp = unpack('Nlength', $this->_string_shift($signature, 4));
  4017. $s = new BigInteger($this->_string_shift($signature, $temp['length']), 256);
  4018. // validate an RSA signature per "8.2 RSASSA-PKCS1-v1_5", "5.2.2 RSAVP1", and "9.1 EMSA-PSS" in the
  4019. // following URL:
  4020. // ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.pdf
  4021. // also, see SSHRSA.c (rsa2_verifysig) in PuTTy's source.
  4022. if ($s->compare(new BigInteger()) < 0 || $s->compare($n->subtract(new BigInteger(1))) > 0) {
  4023. user_error('Invalid signature');
  4024. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  4025. }
  4026. $s = $s->modPow($e, $n);
  4027. $s = $s->toBytes();
  4028. $h = pack('N4H*', 0x00302130, 0x0906052B, 0x0E03021A, 0x05000414, sha1($this->exchange_hash));
  4029. $h = chr(0x01) . str_repeat(chr(0xFF), $nLength - 2 - strlen($h)) . $h;
  4030. if ($s != $h) {
  4031. user_error('Bad server signature');
  4032. return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
  4033. }
  4034. break;
  4035. default:
  4036. user_error('Unsupported signature format');
  4037. return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
  4038. }
  4039. return $this->signature_format . ' ' . base64_encode($this->server_public_host_key);
  4040. }
  4041. /**
  4042. * Returns the exit status of an SSH command or false.
  4043. *
  4044. * @return false|int
  4045. * @access public
  4046. */
  4047. function getExitStatus()
  4048. {
  4049. if (is_null($this->exit_status)) {
  4050. return false;
  4051. }
  4052. return $this->exit_status;
  4053. }
  4054. /**
  4055. * Returns the number of columns for the terminal window size.
  4056. *
  4057. * @return int
  4058. * @access public
  4059. */
  4060. function getWindowColumns()
  4061. {
  4062. return $this->windowColumns;
  4063. }
  4064. /**
  4065. * Returns the number of rows for the terminal window size.
  4066. *
  4067. * @return int
  4068. * @access public
  4069. */
  4070. function getWindowRows()
  4071. {
  4072. return $this->windowRows;
  4073. }
  4074. /**
  4075. * Sets the number of columns for the terminal window size.
  4076. *
  4077. * @param int $value
  4078. * @access public
  4079. */
  4080. function setWindowColumns($value)
  4081. {
  4082. $this->windowColumns = $value;
  4083. }
  4084. /**
  4085. * Sets the number of rows for the terminal window size.
  4086. *
  4087. * @param int $value
  4088. * @access public
  4089. */
  4090. function setWindowRows($value)
  4091. {
  4092. $this->windowRows = $value;
  4093. }
  4094. /**
  4095. * Sets the number of columns and rows for the terminal window size.
  4096. *
  4097. * @param int $columns
  4098. * @param int $rows
  4099. * @access public
  4100. */
  4101. function setWindowSize($columns = 80, $rows = 24)
  4102. {
  4103. $this->windowColumns = $columns;
  4104. $this->windowRows = $rows;
  4105. }
  4106. }