PageRenderTime 61ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/apache/apache-lib.pl

https://bitbucket.org/gencer/webmin
Perl | 1993 lines | 1603 code | 109 blank | 281 comment | 306 complexity | 9e5a18ee0d78d16a4d55be2ff74b81b1 MD5 | raw file
Possible License(s): BSD-3-Clause, CC-BY-SA-3.0

Large files files are truncated, but you can click here to view the full file

  1. # apache-lib.pl
  2. # Common functions for apache configuration
  3. BEGIN { push(@INC, ".."); };
  4. use WebminCore;
  5. $directive_type_count = 20;
  6. if ($module_name ne 'htaccess') {
  7. &init_config();
  8. %access = &get_module_acl();
  9. @access_types = $access{'types'} eq '*' ? (0 .. $directive_type_count)
  10. : split(/\s+/, $access{'types'});
  11. }
  12. else {
  13. @access_types = (0 .. $directive_type_count);
  14. }
  15. map { $access_types{$_}++ } @access_types;
  16. $site_file = ($config{'webmin_apache'} || $module_config_directory)."/site";
  17. # Check if a list of supported modules needs to be built. This is done
  18. # if the Apache binary changes, when Webmin is upgraded, or once every five
  19. # minutes if automatic rebuilding is enabled.
  20. if ($module_name ne 'htaccess') {
  21. local %oldsite;
  22. local $httpd = &find_httpd();
  23. local @st = stat($httpd);
  24. &read_file($site_file, \%oldsite);
  25. local @sst = stat($site_file);
  26. if ($oldsite{'path'} ne $httpd ||
  27. $oldsite{'size'} != $st[7] ||
  28. $oldsite{'webmin'} != &get_webmin_version() ||
  29. $config{'auto_mods'} && $sst[9] < time()-5*60) {
  30. # Need to build list of supported modules
  31. local ($ver, $mods) = &httpd_info($httpd);
  32. if ($ver) {
  33. local @mods = map { "$_/$ver" } &configurable_modules();
  34. foreach my $m (@mods) {
  35. if ($m =~ /(\S+)\/(\S+)/) {
  36. $httpd_modules{$1} = $2;
  37. }
  38. }
  39. # Call again now that known modules have been set, as
  40. # sometimes there are dependencies due to LoadModule
  41. # statements in an IfModule block
  42. @mods = map { "$_/$ver" } &configurable_modules();
  43. local %site = ( 'size' => $st[7],
  44. 'path' => $httpd,
  45. 'modules' => join(' ', @mods),
  46. 'webmin' => &get_webmin_version() );
  47. &lock_file($site_file);
  48. &write_file($site_file, \%site);
  49. chmod(0644, $site_file);
  50. &unlock_file($site_file);
  51. }
  52. }
  53. }
  54. # Read the site-specific setup file, then require in all the module-specific
  55. # .pl files
  56. if (&read_file($site_file, \%site)) {
  57. local($m, $f, $d);
  58. $httpd_size = $site{'size'};
  59. foreach $m (split(/\s+/, $site{'modules'})) {
  60. if ($m =~ /(\S+)\/(\S+)/) {
  61. $httpd_modules{$1} = $2;
  62. }
  63. }
  64. foreach $m (keys %httpd_modules) {
  65. if (!-r "$module_root_directory/$m.pl") {
  66. delete($httpd_modules{$m});
  67. }
  68. }
  69. foreach $f (split(/\s+/, $site{'htaccess'})) {
  70. if (-r $f) { push(@htaccess_files, $f); }
  71. }
  72. foreach $m (keys %httpd_modules) {
  73. do "$m.pl";
  74. }
  75. foreach $d (split(/\s+/, $site{'defines'})) {
  76. $httpd_defines{$d}++;
  77. }
  78. }
  79. $apache_docbase = $config{'apache_docbase'} ? $config{'apache_docbase'} :
  80. $httpd_modules{'core'} >= 2.0 ?
  81. "http://httpd.apache.org/docs-2.0/mod/" :
  82. "http://httpd.apache.org/docs/mod/";
  83. # parse_config_file(handle, lines, file, [recursive])
  84. # Parses lines of text from some config file into a data structure. The
  85. # return value is an array of references, one for each directive in the file.
  86. # Each reference points to an associative array containing
  87. # line - The line number this directive is at
  88. # eline - The line number this directive ends at
  89. # file - The file this directive is from
  90. # type - 0 for a normal directive, 1 for a container directive
  91. # name - The name of this directive
  92. # value - Value (possibly with spaces)
  93. # members - For type 1, a reference to the array of members
  94. sub parse_config_file
  95. {
  96. local($fh, @rv, $line, %dummy);
  97. $fh = $_[0];
  98. $dummy{'line'} = $dummy{'eline'} = $_[1]-1;
  99. $dummy{'file'} = $_[2];
  100. $dummy{'type'} = 0;
  101. $dummy{'name'} = "dummy";
  102. @rv = (\%dummy);
  103. local %defs;
  104. foreach my $d (&get_httpd_defines()) {
  105. if ($d =~ /^(\S+)=(.*)$/) {
  106. $defs{$1} = $2;
  107. }
  108. else {
  109. $defs{$d} = '';
  110. }
  111. }
  112. while($line = <$fh>) {
  113. chop;
  114. $line =~ s/^\s*#.*$//g;
  115. if ($line =~ /^\s*<\/(\S+)\s*(.*)>/) {
  116. # end of a container directive. This can only happen in a
  117. # recursive call to this function
  118. $_[1]++;
  119. last if (lc($_[3]) eq lc($1));
  120. }
  121. elsif ($line =~ /^\s*<IfModule\s+(\!?)(\S+)\.c>/i ||
  122. $line =~ /^\s*<IfModule\s+(\!?)(\S+)>/i) {
  123. # start of an IfModule block. Read it, and if the module
  124. # exists put the directives in this section.
  125. local ($not, $mod) = ($1, $2);
  126. local $oldline = $_[1];
  127. $_[1]++;
  128. local @dirs = &parse_config_file($fh, $_[1], $_[2], 'IfModule');
  129. local $altmod = $mod;
  130. $altmod =~ s/^(\S+)_module$/mod_$1/g;
  131. local $mpmmod = $mod;
  132. $mpmmod =~ s/^mpm_//; $mpmmod =~ s/_module$//;
  133. if (!$not && $httpd_modules{$mod} ||
  134. $not && !$httpd_modules{$mod} ||
  135. !$not && $httpd_modules{$altmod} ||
  136. $not && !$httpd_modules{$altmod} ||
  137. !$not && $httpd_modules{$mpmmod} ||
  138. $not && !$httpd_modules{$mpmmod}
  139. ) {
  140. # use the directives..
  141. push(@rv, { 'line', $oldline,
  142. 'eline', $oldline,
  143. 'file', $_[2],
  144. 'name', "<IfModule $not$mod>" });
  145. push(@rv, @dirs);
  146. push(@rv, { 'line', $_[1]-1,
  147. 'eline', $_[1]-1,
  148. 'file', $_[2],
  149. 'name', "</IfModule>" });
  150. }
  151. }
  152. elsif ($line =~ /^\s*<IfDefine\s+(\!?)(\S+)>/i) {
  153. # start of an IfDefine block. Read it, and if the define
  154. # exists put the directives in this section
  155. local ($not, $def) = ($1, $2);
  156. local $oldline = $_[1];
  157. $_[1]++;
  158. local @dirs = &parse_config_file($fh, $_[1], $_[2], 'IfDefine');
  159. if (!$not && defined($defs{$def}) ||
  160. $not && !defined($defs{$def})) {
  161. # use the directives..
  162. push(@rv, { 'line', $oldline,
  163. 'eline', $oldline,
  164. 'file', $_[2],
  165. 'name', "<IfDefine $not$def>" });
  166. push(@rv, @dirs);
  167. push(@rv, { 'line', $_[1]-1,
  168. 'eline', $_[1]-1,
  169. 'file', $_[2],
  170. 'name', "</IfDefine>" });
  171. }
  172. }
  173. elsif ($line =~ /^\s*<IfVersion\s+(\!?)(\S*)\s*(\S+)>/i) {
  174. # Start of an IfVersion block. Read it, and if the version
  175. # matches put the directives in this section
  176. local ($not, $op, $ver) = ($1, $2, $3);
  177. local $oldline = $_[1];
  178. $_[1]++;
  179. local @dirs = &parse_config_file($fh, $_[1], $_[2], 'IfVersion');
  180. $op ||= "=";
  181. local $match = 0;
  182. local $myver = $httpd_modules{'core'};
  183. $myver =~ s/^(\d+)\.(\d)(\d+)$/$1.$2.$3/;
  184. if ($op eq "=" || $op eq "==") {
  185. if ($ver =~ /^\/(.*)\/$/) {
  186. $match = 1 if ($myver =~ /$1/);
  187. }
  188. else {
  189. $match = 1 if ($myver eq $ver);
  190. }
  191. }
  192. elsif ($op eq ">") {
  193. $match = 1 if ($myver > $ver);
  194. }
  195. elsif ($op eq ">=") {
  196. $match = 1 if ($myver >= $ver);
  197. }
  198. elsif ($op eq "<") {
  199. $match = 1 if ($myver < $ver);
  200. }
  201. elsif ($op eq "<=") {
  202. $match = 1 if ($myver <= $ver);
  203. }
  204. elsif ($op eq "~") {
  205. $match = 1 if ($myver =~ /$ver/);
  206. }
  207. $match = !$match if ($not);
  208. if ($match) {
  209. # use the directives..
  210. push(@rv, { 'line', $oldline,
  211. 'eline', $oldline,
  212. 'file', $_[2],
  213. 'name', "<IfVersion $not$op $ver>" });
  214. push(@rv, @dirs);
  215. push(@rv, { 'line', $_[1]-1,
  216. 'eline', $_[1]-1,
  217. 'file', $_[2],
  218. 'name', "</IfVersion>" });
  219. }
  220. }
  221. elsif ($line =~ /^\s*<(\S+)\s*(.*)>/) {
  222. # start of a container directive. The first member is a dummy
  223. # directive at the same line as the container
  224. local(%dir, @members);
  225. %dir = ('line', $_[1],
  226. 'file', $_[2],
  227. 'type', 1,
  228. 'name', $1,
  229. 'value', $2);
  230. $dir{'value'} =~ s/\s+$//g;
  231. $dir{'words'} = &wsplit($dir{'value'});
  232. $_[1]++;
  233. @members = &parse_config_file($fh, $_[1], $_[2], $dir{'name'});
  234. $dir{'members'} = \@members;
  235. $dir{'eline'} = $_[1]-1;
  236. push(@rv, \%dir);
  237. }
  238. elsif ($line =~ /^\s*(\S+)\s*(.*)$/) {
  239. # normal directive
  240. local(%dir);
  241. %dir = ('line', $_[1],
  242. 'eline', $_[1],
  243. 'file', $_[2],
  244. 'type', 0,
  245. 'name', $1,
  246. 'value', $2);
  247. if ($dir{'value'} =~ s/\\$//g) {
  248. # multi-line directive!
  249. while($line = <$fh>) {
  250. chop($line);
  251. $cont = ($line =~ s/\\$//g);
  252. $dir{'value'} .= $line;
  253. $dir{'eline'} = ++$_[1];
  254. if (!$cont) { last; }
  255. }
  256. }
  257. $dir{'value'} =~ s/\s+$//g;
  258. if ($dir{'value'} =~ /^(.*)\$\{([^\}]+)\}(.*)$/) {
  259. # Contains a variable .. replace with define
  260. local $v = $defs{$2};
  261. if ($v) {
  262. $dir{'value'} = $1.$v.$3;
  263. }
  264. }
  265. $dir{'words'} = &wsplit($dir{'value'});
  266. push(@rv, \%dir);
  267. $_[1]++;
  268. }
  269. else {
  270. # blank or comment line
  271. $_[1]++;
  272. }
  273. }
  274. return @rv;
  275. }
  276. # wsplit(string)
  277. # Splits a string like foo "foo \"bar\"" bazzz into an array of words
  278. sub wsplit
  279. {
  280. local($s, @rv); $s = $_[0];
  281. $s =~ s/\\\"/\0/g;
  282. while($s =~ /^"([^"]*)"\s*(.*)$/ || $s =~ /^(\S+)\s*(.*)$/) {
  283. $w = $1; $s = $2;
  284. $w =~ s/\0/"/g; push(@rv, $w);
  285. }
  286. return \@rv;
  287. }
  288. # wjoin(word, word, ...)
  289. sub wjoin
  290. {
  291. local(@rv, $w);
  292. foreach $w (@_) {
  293. if ($w =~ /^\S+$/) { push(@rv, $w); }
  294. else { push(@rv, "\"$w\""); }
  295. }
  296. return join(' ', @rv);
  297. }
  298. # find_directive(name, &directives, [1stword])
  299. # Returns the values of directives matching some name
  300. sub find_directive
  301. {
  302. local (@vals, $ref);
  303. foreach $ref (@{$_[1]}) {
  304. if (lc($ref->{'name'}) eq lc($_[0])) {
  305. push(@vals, $_[2] ? $ref->{'words'}->[0] : $ref->{'value'});
  306. }
  307. }
  308. return wantarray ? @vals : !@vals ? undef : $vals[$#vals];
  309. }
  310. # find_directive_struct(name, &directives)
  311. # Returns references to directives maching some name
  312. sub find_directive_struct
  313. {
  314. local (@vals, $ref);
  315. foreach $ref (@{$_[1]}) {
  316. if (lc($ref->{'name'}) eq lc($_[0])) {
  317. push(@vals, $ref);
  318. }
  319. }
  320. return wantarray ? @vals : !@vals ? undef : $vals[$#vals];
  321. }
  322. # find_vdirective(name, &virtualdirectives, &directives, [1stword])
  323. # Looks for some directive in a <VirtualHost> section, and then in the
  324. # main section
  325. sub find_vdirective
  326. {
  327. if ($_[1]) {
  328. $rv = &find_directive($_[0], $_[1], $_[3]);
  329. if ($rv) { return $rv; }
  330. }
  331. return &find_directive($_[0], $_[2], $_[3]);
  332. }
  333. # get_config()
  334. # Returns the entire config structure
  335. sub get_config
  336. {
  337. local($acc, $res, $lnum, $conf, @virt, $v, $mref, $inc);
  338. if (@get_config_cache) {
  339. return \@get_config_cache;
  340. }
  341. # read primary config file
  342. ($conf) = &find_httpd_conf();
  343. return undef if (!$conf);
  344. my %seenfiles;
  345. @get_config_cache = &get_config_file($conf, \%seenfiles);
  346. # Read main resource and access config files
  347. $lnum = 0;
  348. $res = &find_directive("ResourceConfig", \@get_config_cache);
  349. if (!$res) { $res = $config{'srm_conf'}; }
  350. if (!$res) { $res = "$config{'httpd_dir'}/conf/srm.conf"; }
  351. if (!-r &translate_filename($res)) {
  352. $res = "$config{'httpd_dir'}/etc/srm.conf";
  353. }
  354. push(@get_config_cache, &get_config_file($res, \%seenfiles));
  355. $lnum = 0;
  356. $acc = &find_directive("AccessConfig", \@get_config_cache);
  357. if (!$acc) { $acc = $config{'access_conf'}; }
  358. if (!$acc) { $acc = "$config{'httpd_dir'}/conf/access.conf"; }
  359. if (!-r &translate_filename($acc)) {
  360. $acc = "$config{'httpd_dir'}/etc/access.conf";
  361. }
  362. push(@get_config_cache, &get_config_file($acc, \%seenfiles));
  363. # Read extra config files in VirtualHost sections
  364. @virt = &find_directive_struct("VirtualHost", \@get_config_cache);
  365. foreach $v (@virt) {
  366. my %seenfiles;
  367. $mref = $v->{'members'};
  368. foreach $idn ("ResourceConfig", "AccessConfig", "Include", "IncludeOptional") {
  369. foreach $inc (&find_directive_struct($idn, $mref)) {
  370. local @incs = &expand_apache_include(
  371. $inc->{'words'}->[0]);
  372. foreach my $ginc (@incs) {
  373. push(@$mref, &get_config_file($ginc,
  374. \%seenfiles));
  375. }
  376. }
  377. }
  378. }
  379. return \@get_config_cache;
  380. }
  381. # get_config_file(filename, [&seen-files])
  382. # Returns a list of config hash refs from some file
  383. sub get_config_file
  384. {
  385. my ($file, $seen) = @_;
  386. # Convert sites-enabled to real path in sites-available
  387. $file = &simplify_path(&resolve_links($file));
  388. return ( ) if ($seen && $seen->{$file}++);
  389. local @rv;
  390. if (opendir(DIR, $file)) {
  391. # Is a directory .. parse all files!
  392. local @files = readdir(DIR);
  393. closedir(DIR);
  394. foreach my $f (sort { $a cmp $b } @files) {
  395. next if ($f =~ /^\./);
  396. push(@rv, &get_config_file("$file/$f", $seen));
  397. }
  398. }
  399. else {
  400. # Just a normal config file
  401. local $lnum = 0;
  402. &open_readfile(CONF, $file);
  403. @rv = &parse_config_file(CONF, $lnum, $file);
  404. close(CONF);
  405. }
  406. # Expand Include directives
  407. foreach $inc (&find_directive_struct("Include", \@rv),
  408. &find_directive_struct("IncludeOptional", \@rv)) {
  409. local @incs = &expand_apache_include($inc->{'words'}->[0]);
  410. foreach my $ginc (@incs) {
  411. push(@rv, &get_config_file($ginc, $seen));
  412. }
  413. }
  414. return @rv;
  415. }
  416. # expand_apache_include(dir)
  417. # Given an include directive value, returns a list of matching files
  418. sub expand_apache_include
  419. {
  420. local ($incdir) = @_;
  421. if ($incdir !~ /^\//) { $incdir = "$config{'httpd_dir'}/$incdir"; }
  422. if ($incdir =~ /^(.*)\[\^([^\]]+)\](.*)$/) {
  423. # A glob like /etc/[^.#]*.conf , which cannot be handled
  424. # by Perl's glob function!
  425. local $before = $1;
  426. local $after = $3;
  427. local %reject = map { $_, 1 } split(//, $2);
  428. $reject{'*'} = $reject{'?'} = $reject{'['} = $reject{']'} =
  429. $reject{'/'} = $reject{'$'} = $reject{'('} = $reject{')'} =
  430. $reject{'!'} = 1;
  431. local $accept = join("", grep { !$reject{$_} } map { chr($_) } (32 .. 126));
  432. $incdir = $before."[".$accept."]".$after;
  433. }
  434. return sort { $a cmp $b } glob($incdir);
  435. }
  436. # get_virtual_config(index|name)
  437. # Returns the Apache config block with some index in the main config, or name
  438. sub get_virtual_config
  439. {
  440. local ($name) = @_;
  441. local $conf = &get_config();
  442. local ($c, $v);
  443. if (!$name) {
  444. # Whole config
  445. $c = $conf;
  446. $v = undef;
  447. }
  448. elsif ($name =~ /^\d+$/) {
  449. # By index
  450. $c = $conf->[$name]->{'members'};
  451. $v = $conf->[$name];
  452. }
  453. else {
  454. # Find by name, in servername:port format
  455. my ($sn, $sp) = split(/:/, $name);
  456. VHOST: foreach my $virt (&find_directive_struct("VirtualHost", $conf)) {
  457. local $vp = $virt->{'words'}->[0] =~ /:(\d+)$/ ? $1 : 80;
  458. next if ($vp != $sp);
  459. local $vn = &find_directive("ServerName", $virt->{'members'});
  460. if (lc($vn) eq lc($sn) || lc($vn) eq lc("www.".$sn)) {
  461. $c = $virt->{'members'};
  462. $v = $virt;
  463. last VHOST;
  464. }
  465. foreach my $n (&find_directive_struct("ServerAlias",
  466. $virt->{'members'})) {
  467. local @lcw = map { lc($_) } @{$n->{'words'}};
  468. if (&indexof($sn, @lcw) >= 0 ||
  469. &indexof("www.".$sn, @lcw) >= 0) {
  470. $c = $virt->{'members'};
  471. $v = $virt;
  472. last VHOST;
  473. }
  474. }
  475. }
  476. }
  477. return wantarray ? ($c, $v) : $c;
  478. }
  479. # get_htaccess_config(file)
  480. sub get_htaccess_config
  481. {
  482. local($lnum, @conf);
  483. &open_readfile(HTACCESS, $_[0]);
  484. @conf = &parse_config_file(HTACCESS, $lnum, $_[0]);
  485. close(HTACCESS);
  486. return \@conf;
  487. }
  488. # save_directive(name, &values, &parent-directives, &config, [always-at-end])
  489. # Updates the config file(s) and the directives structure with new values
  490. # for the given directives.
  491. # If a directive's value is merely being changed, then its value only needs
  492. # to be updated in the directives array and in the file.
  493. sub save_directive
  494. {
  495. local($i, @old, $lref, $change, $len, $v);
  496. @old = &find_directive_struct($_[0], $_[2]);
  497. local @files;
  498. for($i=0; $i<@old || $i<@{$_[1]}; $i++) {
  499. $v = ${$_[1]}[$i];
  500. if ($i >= @old) {
  501. # a new directive is being added. If other directives of this
  502. # type exist, add it after them. Otherwise, put it at the end of
  503. # the first file in the section
  504. if ($change && !$_[4]) {
  505. # Have changed some old directive.. add this new one
  506. # after it, and update change
  507. local(%v, $j);
  508. %v = ( "line", $change->{'line'}+1,
  509. "eline", $change->{'line'}+1,
  510. "file", $change->{'file'},
  511. "type", 0,
  512. "name", $_[0],
  513. "value", $v,
  514. "words", &wsplit($v) );
  515. $j = &indexof($change, @{$_[2]})+1;
  516. &renumber($_[3], $v{'line'}, $v{'file'}, 1);
  517. splice(@{$_[2]}, $j, 0, \%v);
  518. $lref = &read_file_lines($v{'file'});
  519. push(@files, $v{'file'});
  520. splice(@$lref, $v{'line'}, 0, "$_[0] $v");
  521. $change = \%v;
  522. }
  523. else {
  524. # Adding a new directive to the end of the list
  525. # in this section
  526. local($f, %v, $j);
  527. $f = $_[2]->[0]->{'file'};
  528. for($j=0; $_[2]->[$j]->{'file'} eq $f; $j++) { }
  529. $l = $_[2]->[$j-1]->{'eline'}+1;
  530. %v = ( "line", $l,
  531. "eline", $l,
  532. "file", $f,
  533. "type", 0,
  534. "name", $_[0],
  535. "value", $v,
  536. "words", &wsplit($v) );
  537. &renumber($_[3], $l, $f, 1);
  538. splice(@{$_[2]}, $j, 0, \%v);
  539. $lref = &read_file_lines($f);
  540. push(@files, $f);
  541. splice(@$lref, $l, 0, "$_[0] $v");
  542. }
  543. }
  544. elsif ($i >= @{$_[1]}) {
  545. # a directive was deleted
  546. $lref = &read_file_lines($old[$i]->{'file'});
  547. push(@files, $old[$i]->{'file'});
  548. $idx = &indexof($old[$i], @{$_[2]});
  549. splice(@{$_[2]}, $idx, 1);
  550. $len = $old[$i]->{'eline'} - $old[$i]->{'line'} + 1;
  551. splice(@$lref, $old[$i]->{'line'}, $len);
  552. &renumber($_[3], $old[$i]->{'line'}, $old[$i]->{'file'}, -$len);
  553. }
  554. else {
  555. # just changing the value
  556. $lref = &read_file_lines($old[$i]->{'file'});
  557. push(@files, $old[$i]->{'file'});
  558. $len = $old[$i]->{'eline'} - $old[$i]->{'line'} + 1;
  559. &renumber($_[3], $old[$i]->{'eline'}+1,
  560. $old[$i]->{'file'},1-$len);
  561. $old[$i]->{'value'} = $v;
  562. $old[$i]->{'words'} = &wsplit($v);
  563. $old[$i]->{'eline'} = $old[$i]->{'line'};
  564. splice(@$lref, $old[$i]->{'line'}, $len, "$_[0] $v");
  565. $change = $old[$i];
  566. }
  567. }
  568. return &unique(@files);
  569. }
  570. # save_directive_struct(&old-directive, &directive, &parent-directives,
  571. # &config, [firstline-only])
  572. # Updates, creates or removes only multi-line directive like a <virtualhost>
  573. sub save_directive_struct
  574. {
  575. local ($olddir, $newdir, $pconf, $conf, $first) = @_;
  576. return if (!$olddir && !$newdir); # Nothing to do
  577. local $file = $olddir ? $olddir->{'file'} :
  578. $newdir->{'file'} ? $newdir->{'file'} : $pconf->[0]->{'file'};
  579. local $lref = &read_file_lines($file);
  580. local $oldlen = $olddir ? $olddir->{'eline'}-$olddir->{'line'}+1 : undef;
  581. local @newlines = $newdir ? &directive_lines($newdir) : ( );
  582. if ($olddir && $newdir) {
  583. # Update in place
  584. if ($first) {
  585. # Just changing first and last line, like virtualhost IP
  586. $lref->[$olddir->{'line'}] = $newlines[0];
  587. $lref->[$olddir->{'eline'}] = $newlines[$#newlines];
  588. $olddir->{'name'} = $newdir->{'name'};
  589. $olddir->{'value'} = $newdir->{'value'};
  590. }
  591. else {
  592. # Re-writing whole block
  593. &renumber($conf, $olddir->{'eline'}+1, $file,
  594. scalar(@newlines)-$oldlen);
  595. local $idx = &indexof($olddir, @$pconf);
  596. $pconf->[$idx] = $newdir if ($idx >= 0);
  597. $newdir->{'file'} = $olddir->{'file'};
  598. $newdir->{'line'} = $olddir->{'line'};
  599. $newdir->{'eline'} = $olddir->{'line'}+scalar(@newlines)-1;
  600. splice(@$lref, $olddir->{'line'}, $oldlen, @newlines);
  601. # Update sub-directive lines and files too
  602. if ($newdir->{'type'}) {
  603. &recursive_set_lines_files($newdir->{'members'},
  604. $newdir->{'line'}+1,
  605. $newdir->{'file'});
  606. }
  607. }
  608. }
  609. elsif ($olddir && !$newdir) {
  610. # Remove
  611. splice(@$lref, $olddir->{'line'}, $oldlen);
  612. local $idx = &indexof($olddir, @$pconf);
  613. splice(@$pconf, $idx, 1) if ($idx >= 0);
  614. &renumber($conf, $olddir->{'line'}, $olddir->{'file'}, -$oldlen);
  615. }
  616. elsif (!$olddir && $newdir) {
  617. # Add to file, at end of specific file or parent section
  618. local ($addline, $addpos);
  619. if ($newdir->{'file'}) {
  620. $addline = scalar(@$lref);
  621. $addpos = scalar(@$pconf);
  622. }
  623. else {
  624. for($addpos=0; $addpos < scalar(@$pconf) &&
  625. $pconf->[$addpos]->{'file'} eq $file;
  626. $addpos++) {
  627. # Find last parent directive in same file
  628. }
  629. $addpos--;
  630. $addline = $pconf->[$addpos]->{'eline'}+1;
  631. }
  632. $newdir->{'file'} = $file;
  633. $newdir->{'line'} = $addline;
  634. $newdir->{'eline'} = $addline + scalar(@newlines) - 1;
  635. &renumber($conf, $addline, $file, scalar(@newlines));
  636. splice(@$pconf, $addpos, 0, $newdir);
  637. splice(@$lref, $addline, 0, @newlines);
  638. # Update sub-directive lines and files too
  639. if ($newdir->{'type'}) {
  640. &recursive_set_lines_files($newdir->{'members'},
  641. $newdir->{'line'}+1,
  642. $newdir->{'file'});
  643. }
  644. }
  645. }
  646. # recursive_set_lines_files(&directives, first-line, file)
  647. # Update the line numbers and filenames in a list of directives
  648. sub recursive_set_lines_files
  649. {
  650. local ($dirs, $line, $file) = @_;
  651. foreach my $d (@$dirs) {
  652. $dir->{'line'} = $line;
  653. $dir->{'file'} = $file;
  654. if ($dir->{'type'}) {
  655. # Do sub-members too
  656. &recursive_set_lines_files($dir->{'members'}, $line+1, $file);
  657. $line += scalar(@{$dir->{'members'}})+1;
  658. $dir->{'eline'} = $line;
  659. }
  660. else {
  661. $dir->{'eline'} = $line;
  662. }
  663. $line++;
  664. }
  665. return $line;
  666. }
  667. # delete_file_if_empty(file)
  668. # If a virtual host file is now empty, delete it (and any link to it)
  669. sub delete_file_if_empty
  670. {
  671. local ($file) = @_;
  672. local $lref = &read_file_lines($file, 1);
  673. foreach my $l (@$lref) {
  674. return 0 if ($l =~ /\S/);
  675. }
  676. &unflush_file_lines($file);
  677. unlink($file);
  678. &delete_webfile_link($file);
  679. }
  680. # renumber(&config, line, file, offset)
  681. # Recursively changes the line number of all directives from some file
  682. # beyond the given line.
  683. sub renumber
  684. {
  685. local($d);
  686. if (!$_[3]) { return; }
  687. foreach $d (@{$_[0]}) {
  688. if ($d->{'file'} eq $_[2] && $d->{'line'} >= $_[1]) {
  689. $d->{'line'} += $_[3];
  690. }
  691. if ($d->{'file'} eq $_[2] && $d->{'eline'} >= $_[1]) {
  692. $d->{'eline'} += $_[3];
  693. }
  694. if ($d->{'type'}) {
  695. &renumber($d->{'members'}, $_[1], $_[2], $_[3]);
  696. }
  697. }
  698. }
  699. # server_root(path)
  700. # Convert a relative path to being under the server root
  701. sub server_root
  702. {
  703. if (!$_[0]) { return undef; }
  704. elsif ($_[0] =~ /^\//) { return $_[0]; }
  705. else { return "$config{'httpd_dir'}/$_[0]"; }
  706. }
  707. sub dump_config
  708. {
  709. local($c, $mref);
  710. print "<table border>\n";
  711. print "<tr> <td>Name</td> <td>Value</td> <td>File</td> <td>Line</td> </tr>\n";
  712. foreach $c (@_) {
  713. printf "<tr> <td>%s</td> <td>%s</td><td>%s</td><td>%s</td> </tr>\n",
  714. $c->{'name'}, $c->{'value'}, $c->{'file'}, $c->{'line'};
  715. if ($c->{'type'}) {
  716. print "<tr> <td colspan=4>\n";
  717. $mref = $c->{'members'};
  718. &dump_config(@$mref);
  719. print "</td> </tr>\n";
  720. }
  721. }
  722. print "</table>\n";
  723. }
  724. sub def
  725. {
  726. return $_[0] ? $_[0] : $_[1];
  727. }
  728. # make_directives(ref, version, module)
  729. sub make_directives
  730. {
  731. local(@rv, $aref);
  732. $aref = $_[0];
  733. local $ver = $_[1];
  734. if ($ver =~ /^(1)\.(3)(\d+)$/) {
  735. $ver = sprintf "%d.%d%2.2d", $1, $2, $3;
  736. }
  737. foreach $d (@$aref) {
  738. local(%dir);
  739. $dir{'name'} = $d->[0];
  740. $dir{'multiple'} = $d->[1];
  741. $dir{'type'} = int($d->[2]);
  742. $dir{'subtype'} = $d->[2] - $dir{'type'};
  743. $dir{'module'} = $_[2];
  744. $dir{'version'} = $ver;
  745. $dir{'priority'} = $d->[5];
  746. foreach $c (split(/\s+/, $d->[3])) { $dir{$c}++; }
  747. if (!$d->[4]) { push(@rv, \%dir); }
  748. elsif ($d->[4] =~ /^-([\d\.]+)$/ && $ver < $1) { push(@rv, \%dir); }
  749. elsif ($d->[4] =~ /^([\d\.]+)$/ && $ver >= $1) { push(@rv, \%dir); }
  750. elsif ($d->[4] =~ /^([\d\.]+)-([\d\.]+)$/ && $ver >= $1 && $ver < $2)
  751. { push(@rv, \%dir); }
  752. }
  753. return @rv;
  754. }
  755. # editable_directives(type, context)
  756. # Returns an array of references to associative arrays, one for each
  757. # directive of the given type that can be used in the given context
  758. sub editable_directives
  759. {
  760. local($m, $func, @rv, %done);
  761. foreach $m (keys %httpd_modules) {
  762. $func = $m."_directives";
  763. if (defined(&$func)) {
  764. push(@rv, &$func($httpd_modules{$m}));
  765. }
  766. }
  767. @rv = grep { $_->{'type'} == $_[0] && $_->{$_[1]} &&
  768. !$done{$_->{'name'}}++ } @rv;
  769. @rv = grep { &can_edit_directive($_->{'name'}) } @rv;
  770. @rv = sort { local $td = $a->{'subtype'} <=> $b->{'subtype'};
  771. local $pd = $b->{'priority'} <=> $a->{'priority'};
  772. local $md = $a->{'module'} cmp $b->{'module'};
  773. $td ? $td : $pd ? $pd : $md ? $md : $a->{'name'} cmp $b->{'name'} }
  774. @rv;
  775. return @rv;
  776. }
  777. # can_edit_directive(name)
  778. # Returns 1 if the Apache directive named can be edited by the current user
  779. sub can_edit_directive
  780. {
  781. local ($name) = @_;
  782. if ($access{'dirsmode'} == 0) {
  783. return 1;
  784. }
  785. else {
  786. local %dirs = map { lc($_), 1 } split(/\s+/, $access{'dirs'});
  787. if ($access{'dirsmode'} == 1) {
  788. return $dirs{lc($name)};
  789. }
  790. else {
  791. return !$dirs{lc($name)};
  792. }
  793. }
  794. }
  795. # generate_inputs(&editors, &directives, [&skip])
  796. # Displays a 2-column list of options, for use inside a table
  797. sub generate_inputs
  798. {
  799. local($e, $sw, @args, @rv, $func, $lastsub);
  800. foreach $e (@{$_[0]}) {
  801. if (defined($lastsub) && $lastsub != $e->{'subtype'}) {
  802. print &ui_table_hr();
  803. }
  804. $lastsub = $e->{'subtype'};
  805. # Build arg list for the editing function. Each arg can be a single
  806. # directive struct, or a reference to an array of structures.
  807. $func = "edit";
  808. undef(@args);
  809. foreach $ed (split(/\s+/, $e->{'name'})) {
  810. local(@vals);
  811. $func .= "_$ed";
  812. @vals = &find_directive_struct($ed, $_[1]);
  813. if ($e->{'multiple'}) { push(@args, \@vals); }
  814. elsif (!@vals) { push(@args, undef); }
  815. else { push(@args, $vals[$#vals]); }
  816. }
  817. push(@args, $e);
  818. # call the function
  819. @rv = &$func(@args);
  820. local $names;
  821. if ($config{'show_names'} || $userconfig{'show_names'}) {
  822. $names = " (";
  823. foreach $ed (split(/\s+/, $e->{'name'})) {
  824. # nodo50 v0.1 - Change 000004 - Open new window for Help in Apache module and mod_apachessl Help from http://www.apache-ssl.org and
  825. # nodo50 v0.1 - Change 000004 - Abre nueva ventana para Ayuda del módulo Apache y para mod_apachessl busca la Ayuda en http://www.apache-ssl.org and
  826. $names .= "<tt>".&ui_link( ($e->{'module'} eq 'mod_apachessl' ? 'http://www.apache-ssl.org/docs.html#'.$ed : $apache_docbase."/".$e->{'module'}.".html#".lc($ed)), $ed )."</tt>&nbsp;";
  827. #$names .= "<tt><a href='".$apache_docbase."/".$e->{'module'}.".html#".lc($ed)."'>".$ed."</a></tt> ";
  828. # nodo50 v0.1 - Change 000004 - End
  829. }
  830. $names .= ")";
  831. }
  832. if ($rv[0] >= 2) {
  833. # spans 2 columns..
  834. if ($rv[0] == 3) {
  835. # Takes up whole row
  836. print &ui_table_row(undef, $rv[2], 4);
  837. }
  838. else {
  839. # Has title on left
  840. print &ui_table_row($rv[1], $rv[2], 3);
  841. }
  842. }
  843. else {
  844. # only spans one column
  845. print &ui_table_row($rv[1], $rv[2]);
  846. }
  847. }
  848. }
  849. # parse_inputs(&editors, &directives, &config)
  850. # Reads user choices from a form and update the directives and config files.
  851. sub parse_inputs
  852. {
  853. # First call editor functions to get new values. Each function returns
  854. # an array of references to arrays containing the new values for the directive.
  855. &before_changing();
  856. &lock_apache_files();
  857. foreach $e (@{$_[0]}) {
  858. @dirs = split(/\s+/, $e->{'name'});
  859. $func = "save_".join('_', @dirs);
  860. @rv = &$func($e);
  861. for($i=0; $i<@dirs; $i++) {
  862. push(@chname, $dirs[$i]);
  863. push(@chval, $rv[$i]);
  864. }
  865. }
  866. # Assuming everything went OK, update the configuration
  867. for($i=0; $i<@chname; $i++) {
  868. &save_directive($chname[$i], $chval[$i], $_[1], $_[2]);
  869. }
  870. &flush_file_lines();
  871. &unlock_apache_files();
  872. &after_changing();
  873. }
  874. # opt_input(value, name, default, size)
  875. sub opt_input
  876. {
  877. return &ui_opt_textbox($_[1], $_[0], $_[3], $_[2]);
  878. }
  879. # parse_opt(name, regexp, error, [noquotes])
  880. sub parse_opt
  881. {
  882. local($i, $re);
  883. local $v = $in{$_[0]};
  884. if ($in{"$_[0]_def"}) { return ( [ ] ); }
  885. for($i=1; $i<@_; $i+=2) {
  886. $re = $_[$i];
  887. if ($v !~ /$re/) { &error($_[$i+1]); }
  888. }
  889. return ( [ $v =~ /\s/ && !$_[3] ? "\"$v\"" : $v ] );
  890. }
  891. # choice_input(value, name, default, [choice]+)
  892. # Each choice is a display,value pair
  893. sub choice_input
  894. {
  895. my($i, $rv);
  896. for($i=3; $i<@_; $i++) {
  897. $_[$i] =~ /^([^,]*),(.*)$/;
  898. $rv .= &ui_oneradio($_[1], $2, $1, lc($2) eq lc($_[0]) ||
  899. !defined($_[0]) && lc($2) eq lc($_[2]))."\n";
  900. }
  901. return $rv;
  902. }
  903. # choice_input_vert(value, name, default, [choice]+)
  904. # Each choice is a display,value pair
  905. sub choice_input_vert
  906. {
  907. my($i, $rv);
  908. for($i=3; $i<@_; $i++) {
  909. $_[$i] =~ /^([^,]*),(.*)$/;
  910. $rv .= &ui_oneradio($_[1], $2, $1, lc($2) eq lc($_[0]) ||
  911. !defined($_[0]) && lc($2) eq lc($_[2]))."<br>\n";
  912. }
  913. return $rv;
  914. }
  915. # parse_choice(name, default)
  916. sub parse_choice
  917. {
  918. if (lc($in{$_[0]}) eq lc($_[1])) { return ( [ ] ); }
  919. else { return ( [ $in{$_[0]} ] ); }
  920. }
  921. # select_input(value, name, default, [choice]+)
  922. sub select_input
  923. {
  924. my($i, @sel);
  925. for($i=3; $i<@_; $i++) {
  926. $_[$i] =~ /^([^,]*),(.*)$/;
  927. push(@sel, [$2, $1, (lc($2) eq lc($_[0]) || !defined($_[0]) && lc($2) eq lc($_[2]) ? "selected" : "") ]);
  928. }
  929. return &ui_select($_[1], undef, \@sel, 1);
  930. }
  931. # parse_choice(name, default)
  932. sub parse_select
  933. {
  934. return &parse_choice(@_);
  935. }
  936. # handler_input(value, name)
  937. sub handler_input
  938. {
  939. my($m, $func, @hl, @sel, $h);
  940. my $conf = &get_config();
  941. push(@hl, "");
  942. foreach $m (keys %httpd_modules) {
  943. $func = $m."_handlers";
  944. if (defined(&$func)) {
  945. push(@hl, &$func($conf, $httpd_modules{$m}));
  946. }
  947. }
  948. if (&indexof($_[0], @hl) < 0) { push(@hl, $_[0]); }
  949. foreach $h (&unique(@hl)) {
  950. push(@sel, [$h, $h, ($h eq $_[0] ? "selected" : "")] );
  951. }
  952. push(@sel, ["None", "&lt;".$text{'core_none'}."&gt;", ($_[0] eq "None" ? "selected" : "")] );
  953. return &ui_select($_[1], undef, \@sel, 1);
  954. }
  955. # parse_handler(name)
  956. sub parse_handler
  957. {
  958. if ($in{$_[0]} eq "") { return ( [ ] ); }
  959. else { return ( [ $in{$_[0]} ] ); }
  960. }
  961. # filters_input(&values, name)
  962. sub filters_input
  963. {
  964. local($m, $func, @fl, $rv, $f);
  965. local $conf = &get_config();
  966. foreach $m (keys %httpd_modules) {
  967. $func = $m."_filters";
  968. if (defined(&$func)) {
  969. push(@fl, &$func($conf, $httpd_modules{$m}));
  970. }
  971. }
  972. foreach $f (@{$_[0]}) {
  973. push(@fl, $f) if (&indexof($f, @fl) < 0);
  974. }
  975. foreach $f (&unique(@fl)) {
  976. $rv .= &ui_checkbox($_[1], $f, $f, (&indexof($f, @{$_[0]}) < 0 ? 0 : 1 ) );
  977. }
  978. return $rv;
  979. }
  980. # parse_filters(name)
  981. sub parse_filters
  982. {
  983. local @f = split(/\0/, $in{$_[0]});
  984. return @f ? ( [ join(";", @f) ] ) : ( [ ] );
  985. }
  986. # virtual_name(struct, [forlog])
  987. sub virtual_name
  988. {
  989. if ($_[0]) {
  990. local $n = &find_directive("ServerName", $_[0]->{'members'});
  991. if ($n) {
  992. return &html_escape($_[0]->{'value'} =~ /:(\d+)$/ ? "$n:$1"
  993. : $n);
  994. }
  995. else {
  996. return &html_escape(
  997. $_[0]->{'value'} =~ /^\[(\S+)\]$/ ? $1 :
  998. $_[0]->{'value'} =~ /^\[(\S+)\]:(\d+)$/ ? "$1:$2" :
  999. $_[0]->{'value'});
  1000. }
  1001. }
  1002. else { return $_[1] ? "*" : $text{'default_serv'}; }
  1003. }
  1004. # dir_name(struct)
  1005. # Given a <directory> or similar structure, return a human-readable description
  1006. sub dir_name
  1007. {
  1008. $_[0]->{'name'} =~ /^(Directory|Files|Location|Proxy)(Match)?$/;
  1009. my ($dfm, $mat) = ($1, $2);
  1010. if ($dfm eq "Proxy" && !$mat && $_[0]->{'words'}->[0] eq "*") {
  1011. # Proxy for all
  1012. return $text{'dir_proxyall'};
  1013. }
  1014. elsif ($mat) {
  1015. # Match-type directive
  1016. return "$dfm regexp <tt>".&html_escape($_[0]->{'words'}->[0])."</tt>";
  1017. }
  1018. elsif ($_[0]->{'words'}->[0] eq "~") {
  1019. # Regular expression
  1020. return "$dfm regexp <tt>".&html_escape($_[0]->{'words'}->[1])."</tt>";
  1021. }
  1022. else {
  1023. # Exact match
  1024. return "$dfm <tt>".&html_escape($_[0]->{'words'}->[0])."</tt>";
  1025. }
  1026. }
  1027. # list_user_file(file, &user, &pass)
  1028. sub list_user_file
  1029. {
  1030. local($_);
  1031. &open_readfile(USERS, $_[0]);
  1032. while(<USERS>) {
  1033. /^(\S+):(\S+)/;
  1034. push(@{$_[1]}, $1); $_[2]->{$1} = $2;
  1035. }
  1036. close(USERS);
  1037. }
  1038. # config_icons(context, program)
  1039. # Displays up to 18 icons, one for each type of configuration directive, for
  1040. # some context (global, virtual, directory or htaccess)
  1041. sub config_icons
  1042. {
  1043. local($m, $func, $e, %etype, $i, $c);
  1044. foreach $m (sort { $a cmp $b } (keys %httpd_modules)) {
  1045. $func = $m."_directives";
  1046. if (defined(&$func)) {
  1047. foreach $e (&$func($httpd_modules{$m})) {
  1048. if ($e->{$_[0]}) { $etype{$e->{'type'}}++; }
  1049. }
  1050. }
  1051. }
  1052. local (@titles, @links, @icons);
  1053. for($i=0; $text{"type_$i"}; $i++) {
  1054. if ($etype{$i} && $access_types{$i}) {
  1055. push(@links, $_[1]."type=$i");
  1056. push(@titles, $text{"type_$i"});
  1057. push(@icons, "images/type_icon_$i.gif");
  1058. }
  1059. }
  1060. for($i=2; $i<@_; $i++) {
  1061. if ($_[$i]) {
  1062. push(@links, $_[$i]->{'link'});
  1063. push(@titles, $_[$i]->{'name'});
  1064. push(@icons, $_[$i]->{'icon'});
  1065. }
  1066. }
  1067. &icons_table(\@links, \@titles, \@icons, 5);
  1068. print "<p>\n";
  1069. }
  1070. # restart_button()
  1071. # Returns HTML for a link to put in the top-right corner of every page
  1072. sub restart_button
  1073. {
  1074. local $rv;
  1075. $args = "redir=".&urlize(&this_url());
  1076. local @rv;
  1077. if (&is_apache_running()) {
  1078. if ($access{'apply'}) {
  1079. push(@rv, &ui_link("restart.cgi?$args", $text{'apache_apply'}) );
  1080. }
  1081. if ($access{'stop'}) {
  1082. push(@rv, &ui_link("stop.cgi?$args", $text{'apache_stop'}) );
  1083. }
  1084. }
  1085. elsif ($access{'stop'}) {
  1086. push(@rv, &ui_link("start.cgi?$args", $text{'apache_start'}) );
  1087. }
  1088. return join("<br>\n", @rv);
  1089. }
  1090. # this_url()
  1091. # Returns the URL in the apache directory of the current script
  1092. sub this_url
  1093. {
  1094. local($url);
  1095. $url = $ENV{'SCRIPT_NAME'};
  1096. if ($ENV{'QUERY_STRING'} ne "") { $url .= "?$ENV{'QUERY_STRING'}"; }
  1097. return $url;
  1098. }
  1099. # find_all_directives(config, name)
  1100. # Recursively finds all directives of some type
  1101. sub find_all_directives
  1102. {
  1103. local(@rv, $d);
  1104. foreach $d (@{$_[0]}) {
  1105. if ($d->{'name'} eq $_[1]) { push(@rv, $d); }
  1106. if ($d->{'type'} == 1) {
  1107. push(@rv, &find_all_directives($d->{'members'}, $_[1]));
  1108. }
  1109. }
  1110. return @rv;
  1111. }
  1112. # httpd_info(executable)
  1113. # Returns the httpd version and modules array
  1114. sub httpd_info
  1115. {
  1116. local(@mods, $verstr, $ver, $minor);
  1117. $verstr = &backquote_command("\"$_[0]\" -v 2>&1");
  1118. if ($config{'httpd_version'}) {
  1119. $config{'httpd_version'} =~ /(\d+)\.([\d\.]+)/;
  1120. $ver = $1; $minor = $2; $minor =~ s/\.//g; $ver .= ".$minor";
  1121. }
  1122. elsif ($verstr =~ /Apache(\S*)\/(\d+)\.([\d\.]+)/) {
  1123. # standard apache
  1124. $ver = $2; $minor = $3; $minor =~ s/\.//g; $ver .= ".$minor";
  1125. }
  1126. elsif ($verstr =~ /HP\s*Apache-based\s*Web\s*Server(\S*)\/(\d+)\.([\d\.]+)/) {
  1127. # HP's apache
  1128. $ver = $2; $minor = $3; $minor =~ s/\.//g; $ver .= ".$minor";
  1129. }
  1130. elsif ($verstr =~ /Red\s*Hat\s+Secure\/2\.0/i) {
  1131. # redhat secure server 2.0
  1132. $ver = 1.31;
  1133. }
  1134. elsif ($verstr =~ /Red\s*Hat\s+Secure\/3\.0/i) {
  1135. # redhat secure server 3.0
  1136. $ver = 1.39;
  1137. }
  1138. elsif (&has_command("rpm") &&
  1139. &backquote_command("rpm -q apache 2>&1") =~ /^apache-(\d+)\.([\d\.]+)/) {
  1140. # got version from the RPM
  1141. $ver = $1; $minor = $2; $minor =~ s/\.//g; $ver .= ".$minor";
  1142. }
  1143. else {
  1144. # couldn't get version
  1145. return (0, undef);
  1146. }
  1147. if ($ver < 1.2) {
  1148. # apache 1.1 has no -l option! Use the standard list
  1149. @mods = ("core", "mod_mime", "mod_access", "mod_auth", "mod_include",
  1150. "mod_negotiation", "mod_dir", "mod_cgi", "mod_userdir",
  1151. "mod_alias", "mod_env", "mod_log_common");
  1152. }
  1153. else {
  1154. # ask apache for the module list
  1155. @mods = ("core");
  1156. &open_execute_command(APACHE, "\"$_[0]\" -l 2>/dev/null", 1);
  1157. while(<APACHE>) {
  1158. if (/(\S+)\.c/) { push(@mods, $1); }
  1159. }
  1160. close(APACHE);
  1161. if ($?) {
  1162. # httpd crashed! Use last known good set of modules
  1163. local %oldsite;
  1164. &read_file($site_file, \%oldsite);
  1165. if ($oldsite{'modules'}) {
  1166. @mods = split(/\s+/, $oldsite{'modules'});
  1167. }
  1168. }
  1169. @mods = &unique(@mods);
  1170. }
  1171. return ($ver, \@mods);
  1172. }
  1173. # print_line(directive, text, indent, link)
  1174. sub print_line
  1175. {
  1176. local $line = $_[0]->{'line'} + 1;
  1177. local $lstr = "$_[0]->{'file'} ($line)";
  1178. local $txt = join("", @{$_[1]});
  1179. local $left = 85 - length($lstr) - $_[2];
  1180. if (length($txt) > $left) {
  1181. $txt = substr($txt, 0, $left)." ..";
  1182. }
  1183. local $txtlen = length($txt);
  1184. $txt = &html_escape($txt);
  1185. print " " x $_[2];
  1186. if ($_[3]) {
  1187. print &ui_link($_[3], $txt);
  1188. }
  1189. else { print $txt; }
  1190. print " " x (90 - $txtlen - $_[2] - length($lstr));
  1191. print $lstr,"\n";
  1192. }
  1193. # can_edit_virt(struct)
  1194. sub can_edit_virt
  1195. {
  1196. return 1 if ($access{'virts'} eq '*');
  1197. local %vcan = map { $_, 1 } split(/\s+/, $access{'virts'});
  1198. local ($can) = grep { $vcan{$_} } &virt_acl_name($_[0]);
  1199. return $can ? 1 : 0;
  1200. }
  1201. # virt_acl_name(struct)
  1202. # Give a virtual host, returns a list of names that could be used in the ACL
  1203. # to refer to it
  1204. sub virt_acl_name
  1205. {
  1206. return ( "__default__" ) if (!$_[0]);
  1207. local $n = &find_directive("ServerName", $_[0]->{'members'});
  1208. local @rv;
  1209. local $p;
  1210. if ($_[0]->{'value'} =~ /(:\d+)/) { $p = $1; }
  1211. if ($n) {
  1212. push(@rv, $n.$p);
  1213. }
  1214. else {
  1215. push(@rv, $_[0]->{'value'});
  1216. }
  1217. foreach $n (&find_directive_struct("ServerAlias", $_[0]->{'members'})) {
  1218. local $a;
  1219. foreach $a (@{$n->{'words'}}) {
  1220. push(@rv, $a.$p);
  1221. }
  1222. }
  1223. return @rv;
  1224. }
  1225. # allowed_auth_file(file)
  1226. sub allowed_auth_file
  1227. {
  1228. local $_;
  1229. return 1 if ($access{'dir'} eq '/');
  1230. return 0 if ($_[0] =~ /\.\./);
  1231. local $f = &server_root($_[0], &get_config());
  1232. return 0 if (-l $f && !&allowed_auth_file(readlink($f)));
  1233. local $l = length($access{'dir'});
  1234. return length($f) >= $l && substr($f, 0, $l) eq $access{'dir'};
  1235. }
  1236. # directory_exists(file)
  1237. # Returns 1 if the directory in some path exists
  1238. sub directory_exists
  1239. {
  1240. local $path = &server_root($_[0], &get_config());
  1241. if ($path =~ /^(\S*\/)([^\/]+)$/) {
  1242. return -d $1;
  1243. }
  1244. else {
  1245. return 0;
  1246. }
  1247. }
  1248. # allowed_doc_dir(dir)
  1249. # Returns 1 if some directory is under the allowed root for alias targets
  1250. sub allowed_doc_dir
  1251. {
  1252. return $access{'aliasdir'} eq '/' ||
  1253. $_[0] !~ /^\// || # Relative path, like for <Files>
  1254. &is_under_directory($access{'aliasdir'}, $_[0]);
  1255. }
  1256. sub lock_apache_files
  1257. {
  1258. local $conf = &get_config();
  1259. local $f;
  1260. foreach $f (&unique(map { $_->{'file'} } @$conf)) {
  1261. &lock_file($f);
  1262. }
  1263. }
  1264. sub unlock_apache_files
  1265. {
  1266. local $conf = &get_config();
  1267. local $f;
  1268. foreach $f (&unique(map { $_->{'file'} } @$conf)) {
  1269. &unlock_file($f);
  1270. }
  1271. }
  1272. # directive_lines(directive, ...)
  1273. sub directive_lines
  1274. {
  1275. local @rv;
  1276. foreach $d (@_) {
  1277. next if ($d->{'name'} eq 'dummy');
  1278. if ($d->{'type'}) {
  1279. push(@rv, "<$d->{'name'} $d->{'value'}>");
  1280. push(@rv, &directive_lines(@{$d->{'members'}}));
  1281. push(@rv, "</$d->{'name'}>");
  1282. }
  1283. else {
  1284. push(@rv, "$d->{'name'} $d->{'value'}");
  1285. }
  1286. }
  1287. return @rv;
  1288. }
  1289. # test_config()
  1290. # If possible, test the current configuration and return an error message,
  1291. # or undef.
  1292. sub test_config
  1293. {
  1294. if ($httpd_modules{'core'} >= 1.301) {
  1295. # Test the configuration with the available command
  1296. local $cmd;
  1297. if ($config{'test_apachectl'} &&
  1298. -x &translate_filename($config{'apachectl_path'})) {
  1299. # Test with apachectl
  1300. $cmd = "\"$config{'apachectl_path'}\" configtest";
  1301. }
  1302. else {
  1303. # Test with httpd
  1304. local $httpd = &find_httpd();
  1305. $cmd = "\"$httpd\" -d \"$config{'httpd_dir'}\" -t";
  1306. if ($config{'httpd_conf'}) {
  1307. $cmd .= " -f \"$config{'httpd_conf'}\"";
  1308. }
  1309. foreach $d (&get_httpd_defines()) {
  1310. $cmd .= " -D$d";
  1311. }
  1312. }
  1313. local $out = &backquote_command("$cmd 2>&1");
  1314. if ($out && $out !~ /syntax\s+ok/i) {
  1315. return $out;
  1316. }
  1317. }
  1318. return undef;
  1319. }
  1320. # before_changing()
  1321. # If testing all changes, backup the config files so they can be reverted
  1322. # if necessary.
  1323. sub before_changing
  1324. {
  1325. if ($config{'test_always'} || $access{'test_always'}) {
  1326. local $conf = &get_config();
  1327. local @files = &unique(map { $_->{'file'} } @$conf);
  1328. local $/ = undef;
  1329. local $f;
  1330. foreach $f (@files) {
  1331. if (&open_readfile(BEFORE, $f)) {
  1332. $before_changing{$f} = <BEFORE>;
  1333. close(BEFORE);
  1334. }
  1335. }
  1336. }
  1337. }
  1338. # after_changing()
  1339. # If testing all changes, test now and revert the configs and show an error
  1340. # message if a problem was found.
  1341. sub after_changing
  1342. {
  1343. if ($config{'test_always'} || $access{'test_always'}) {
  1344. local $err = &test_config();
  1345. if ($err) {
  1346. # Something failed .. revert all files
  1347. &rollback_apache_config();
  1348. &error(&text('eafter', "<pre>$err</pre>"));
  1349. }
  1350. }
  1351. }
  1352. # rollback_apache_config()
  1353. # Copy back all config files from their originals
  1354. sub rollback_apache_config
  1355. {
  1356. local $f;
  1357. foreach $f (keys %before_changing) {
  1358. &open_tempfile(AFTER, ">$f");
  1359. &print_tempfile(AFTER, $before_changing{$f});
  1360. &close_tempfile(AFTER);
  1361. }
  1362. }
  1363. # find_httpd_conf()
  1364. # Returns the path to the http.conf file, and the last place looked
  1365. # (without any translation).
  1366. sub find_httpd_conf
  1367. {
  1368. local $conf = $config{'httpd_conf'};
  1369. return ( -f &translate_filename($conf) ? $conf : undef, $conf ) if ($conf);
  1370. $conf = "$config{'httpd_dir'}/conf/httpd.conf";
  1371. $conf = "$config{'httpd_dir'}/conf/httpd2.conf"
  1372. if (!-f &translate_filename($conf));
  1373. $conf = "$config{'httpd_dir'}/etc/httpd.conf"
  1374. if (!-f &translate_filename($conf));
  1375. $conf = "$config{'httpd_dir'}/etc/httpd2.conf"
  1376. if (!-f &translate_filename($conf));
  1377. $conf = undef if (!-f &translate_filename($conf));
  1378. return ( $conf, "$config{'httpd_dir'}/conf/httpd.conf" );
  1379. }
  1380. # find_httpd()
  1381. # Returns the path to the httpd executable, by appending '2' if necessary
  1382. sub find_httpd
  1383. {
  1384. return $config{'httpd_path'}
  1385. if (-x &translate_filename($config{'httpd_path'}) &&
  1386. !-d &translate_filename($config{'httpd_path'}));
  1387. return $config{'httpd_path'}.'2'
  1388. if (-x &translate_filename($config{'httpd_path'}.'2') &&
  1389. !-d &translate_filename($config{'httpd_path'}.'2'));
  1390. return undef;
  1391. }
  1392. # get_pid_file()
  1393. # Returns the path to the PID file (without any translation)
  1394. sub get_pid_file
  1395. {
  1396. return $config{'pid_file'} if ($config{'pid_file'});
  1397. local $conf = &get_config();
  1398. local $pidfilestr = &find_directive_struct("PidFile", $conf);
  1399. local $pidfile = $pidfilestr ? $pidfilestr->{'words'}->[0]
  1400. : "logs/httpd.pid";
  1401. return &server_root($pidfile, $conf);
  1402. }
  1403. # restart_apache()
  1404. # Re-starts Apache, and returns undef on success or an error message on failure
  1405. sub restart_apache
  1406. {
  1407. local $pidfile = &get_pid_file();
  1408. if ($config{'apply_cmd'} eq 'restart') {
  1409. # Call stop and start functions
  1410. local $err = &stop_apache();
  1411. return $err if ($err);
  1412. local $stopped = &wait_for_apache_stop();
  1413. local $err = &start_apache();
  1414. return $err if ($err);
  1415. }
  1416. elsif ($config{'apply_cmd'}) {
  1417. # Use the configured start command
  1418. &clean_environment();
  1419. local $out = &backquote_logged("$config{'apply_cmd'} 2>&1");
  1420. &reset_environment();
  1421. &wait_for_graceful() if ($config{'apply_cmd'} =~ /graceful/);
  1422. if ($?) {
  1423. return "<pre>".&html_escape($out)."</pre>";
  1424. }
  1425. }
  1426. elsif (-x &translate_filename($config{'apachectl_path'})) {
  1427. # Use apachectl to restart
  1428. if ($httpd_modules{'core'} >= 2) {
  1429. # Do a graceful restart
  1430. &clean_environment();
  1431. local $out = &backquote_logged(
  1432. "$config{'apachectl_path'} graceful 2>&1");
  1433. &reset_environment();
  1434. &wait_for_graceful();
  1435. if ($?) {
  1436. return "<pre>".&html_escape($out)."</pre>";
  1437. }
  1438. }
  1439. else {
  1440. &clean_environment();
  1441. local $out = &backquote_logged(
  1442. "$config{'apachectl_path'} restart 2>&1");
  1443. &reset_environment();
  1444. if ($out !~ /httpd restarted/) {
  1445. return "<pre>".&html_escape($out)."</pre>";
  1446. }
  1447. }
  1448. }
  1449. else {
  1450. # send SIGHUP directly
  1451. &open_readfile(PID, $pidfile) || return &text('restart_epid', $pidfile);
  1452. <PID> =~ /(\d+)/ || return &text('restart_epid2', $pidfile);
  1453. close(PID);
  1454. &kill_logged('HUP', $1) || return &text('restart_esig', $1);
  1455. &wait_for_graceful();
  1456. }
  1457. return undef;
  1458. }
  1459. # wait_for_graceful([timeout])
  1460. # Wait for some time for Apache to complete a graceful restart
  1461. sub wait_for_graceful
  1462. {
  1463. local $timeout = $_[0] || 10;
  1464. local $errorlog = &get_error_log();
  1465. return -1 if (!$errorlog || !-r $errorlog);
  1466. local @st = stat($errorlog);
  1467. my $start = time();
  1468. while(time() - $start < $timeout) {
  1469. sleep(1);
  1470. open(ERRORLOG, $errorlog);
  1471. seek(ERRORLOG, $st[7], 0);
  1472. local $/ = undef;
  1473. local $rest = <ERRORLOG>;
  1474. close(ERRORLOG);
  1475. if ($rest =~ /resuming\s+normal\s+operations/i) {
  1476. return 1;
  1477. }
  1478. }
  1479. return 0;
  1480. }
  1481. # stop_apache()
  1482. # Attempts to stop the running Apache process, and returns undef on success or
  1483. # an error message on failure
  1484. sub stop_apache
  1485. {
  1486. local $out;
  1487. if ($config{'stop_cmd'}) {
  1488. # use the configured stop command
  1489. $out = &backquote_logged("($config{'stop_cmd'}) 2>&1");
  1490. if ($?) {
  1491. return "<pre>".&html_escape($out)."</pre>";
  1492. }
  1493. }
  1494. elsif (-x $config{'apachectl_path'}) {
  1495. # use the apachectl program
  1496. $out = &backquote_logged("($config{'apachectl_path'} stop) 2>&1");
  1497. if ($httpd_modules{'core'} >= 2 ? $? : $out !~ /httpd stopped/) {
  1498. return "<pre>".&html_escape($out)."</pre>";
  1499. }
  1500. }
  1501. else {
  1502. # kill the process
  1503. $pidfile = &get_pid_file();
  1504. open(PID, $pidfile) || return &text('stop_epid', $pidfile);
  1505. <PID> =~ /(\d+)/ || return &text('stop_epid2', $pidfile);
  1506. close(PID);
  1507. &kill_logged('TERM', $1) || return &text('stop_esig', $1);
  1508. }
  1509. return undef;
  1510. }
  1511. # start_apache()
  1512. # Attempts to start Apache, and returns undef on success or an error message
  1513. # upon failure.
  1514. sub start_apache
  1515. {
  1516. local ($out, $cmd);
  1517. &clean_environment();
  1518. if ($config{'start_cmd'}) {
  1519. # use the configured start command
  1520. if ($config{'stop_cmd'}) {
  1521. # execute the stop command to clear lock files
  1522. &system_logged("($config{'stop_cmd'}) >/dev/null 2>&1");
  1523. }
  1524. $out = &backquote_logged("($config{'start_cmd'}) 2>&1");
  1525. &reset_environment();
  1526. if ($?) {
  1527. return "<pre>".&html_escape($out)."</pre>";
  1528. }
  1529. }
  1530. elsif (-x $config{'apachectl_path'}) {
  1531. # use the apachectl program
  1532. $cmd = "$config{'apachectl_path'} start";
  1533. $out = &backquote_logged("($cmd) 2>&1");
  1534. &reset_environment();
  1535. }
  1536. else {
  1537. # start manually
  1538. local $httpd = &find_httpd();
  1539. $cmd = "$httpd -d $config{'httpd_dir'}";
  1540. if ($config{'httpd_conf'}) {
  1541. $cmd .= " -f $config{'httpd_conf'}";
  1542. }
  1543. foreach $d (&get_httpd_defines()) {
  1544. $cmd .= " -D$d";
  1545. }
  1546. local $temp = &transname();
  1547. local $rv = &system_logged("( $cmd ) >$temp 2>&1 </dev/null");
  1548. $out = &read_file_contents($temp);
  1549. unlink($temp);
  1550. &reset_environment();
  1551. }
  1552. # Check if Apache may have failed to start
  1553. local $slept;
  1554. if ($out =~ /\S/ && $out !~ /httpd\s+started/i) {
  1555. sleep(3);
  1556. if (!&is_apache_running()) {
  1557. return "<pre>".&html_escape($cmd)." :\n".
  1558. &html_escape($out)."</pre>";
  1559. }
  1560. $slept = 1;
  1561. }
  1562. # check if startup was successful. Later apache version return no
  1563. # error code, but instead fail to start and write the reason to
  1564. # the error log file!
  1565. sleep(3) if (!$slept);
  1566. local $conf = &get_config();
  1567. if (!&is_apache_running()) {
  1568. # Not running.. find out why
  1569. local $errorlogstr = &find_directive_struct("ErrorLog", $conf);
  1570. local $errorlog = $errorlogstr ? $errorlogstr->{'words'}->[0]
  1571. : "logs/error_log";
  1572. if ($out =~ /\S/) {
  1573. return "$text{'start_eafter'} : <pre>$out</pre>";
  1574. }
  1575. elsif ($errorlog eq 'syslog' || $errorlog =~ /^\|/) {
  1576. return $text{'start_eunknown'};
  1577. }
  1578. else {
  1579. $errorlog = &server_root($errorlog, $conf);
  1580. $out = `tail -5 $errorlog`;
  1581. return "$text{'start_eafter'} : <pre>$out</pre>";
  1582. }
  1583. }
  1584. return undef;
  1585. }
  1586. # get_error_log()
  1587. # Returns the path to the global error log, if possible
  1588. sub get_error_log
  1589. {
  1590. local $conf = &get_config();
  1591. local $errorlogstr = &find_directive_struct("ErrorLog", $conf);
  1592. local $errorlog = $errorlogstr ? $errorlogstr->{'words'}->[0]
  1593. : "logs/error_log";
  1594. $errorlog = &server_root($errorlog, $conf);
  1595. return $errorlog;
  1596. }
  1597. sub is_apache_running
  1598. {
  1599. if ($gconfig{'os_type'} eq 'windows') {
  1600. # No such thing as a PID file on Windows
  1601. local ($pid) = &find_byname("Apache.exe");
  1602. return $pid;
  1603. }
  1604. else {
  1605. # Check PID file
  1606. local $pidfile = &get_pid_file();
  1607. return &check_pid_file($pidfile);
  1608. }
  1609. }
  1610. # wait_for_apache_stop([secs])
  1611. # Wait 30 (by default) seconds for Apache to stop. Returns 1 if OK, 0 if not
  1612. sub wait_for_apache_stop
  1613. {
  1614. local $secs = $_[0] || 30;
  1615. for(my $i=0; $i<$secs; $i++) {
  1616. return 1 if (!&is_apache_running());
  1617. sleep(1);
  1618. }
  1619. return 0;
  1620. }
  1621. # configurable_modules()
  1622. # Returns a list of Apaches that are compiled in or dynamically loaded, and
  1623. # supported by Webmin.
  1624. sub configurable_modules
  1625. {
  1626. local ($ver, $mods) = &httpd_info(&find_httpd());
  1627. local @rv;
  1628. local $m;
  1629. # Add compiled-in modules
  1630. foreach $m (@$mods) {
  1631. if (-r "$module_root_directory/$m.pl") {
  1632. push(@rv, $m);
  1633. }
  1634. }
  1635. # Add dynamically loaded modules
  1636. local $conf = &get_config();
  1637. foreach $l (&find_directive_struct("LoadModule", $conf)) {
  1638. if ($l->{'words'}->[1] =~ /(mod_\S+)\.(so|dll)/ &&
  1639. -r "$module_root_directory/$1.pl") {
  1640. push(@rv, $1);
  1641. }
  1642. elsif ($l->{'words'}->[1] =~ /libssl\.so/ &&
  1643. -r "$module_root_directory/mod_apachessl.pl") {
  1644. push(@rv, "mod_apachessl");
  1645. }
  1646. elsif ($l->{'words'}->[1] =~ /lib([^\/\s]+)\.(so|dll)/ &&
  1647. -r "$module_root_directory/mod_$1.pl") {
  1648. push(@rv, "mod_$1");
  1649. }
  1650. }
  1651. undef(@get_config_cache); # Cache is no longer valid
  1652. # Add dynamically loaded modules
  1653. if ($config{'apachectl_path'}) {
  1654. &open_execute_command(APACHE,
  1655. "$config{'apachectl_path'} -M 2>/dev/null", 1);
  1656. while(<APACHE>) {
  1657. if (/(\S+)_module/ && -r "$module_root_directory/mod_${1}.pl") {
  1658. push(@rv, "mod_${1}");
  1659. }
  1660. }
  1661. close(APACHE);
  1662. }
  1663. return &unique(@rv);
  1664. }
  1665. # get_httpd_defines(automatic-only)
  1666. # Returns a list of defines that need to be passed to Apache
  1667. sub get_httpd_defines
  1668. {
  1669. local ($auto) = @_;
  1670. if (@get_httpd_defines_cache) {
  1671. return @get_httpd_defines_cache;
  1672. }
  1673. local @rv;
  1674. if (!$auto) {
  1675. push(@rv, keys %httpd_defines);
  1676. }
  1677. if ($config{'defines_file'}) {
  1678. # Add defines from an environment file, which can be in
  1679. # the format :
  1680. # OPTIONS='-Dfoo -Dbar'
  1681. # or regular name=value format
  1682. local %def;
  1683. &read_env_file($config{'defines_file'}, \%def);
  1684. if ($config{'defines_name'} && $def{$config{'defines_name'}}) {
  1685. # Looking for var like OPTIONS='-Dfoo -Dbar'
  1686. local $var = $def{$config{'defines_name'}};
  1687. foreach my $v (split(/\s+/, $var)) {
  1688. if ($v =~ /^-[Dd](\S+)$/) {
  1689. push(@rv, $1);
  1690. }
  1691. else {
  1692. push(@rv, $v);
  1693. }
  1694. }
  1695. }
  1696. else {
  1697. # Looking for regular name=value directives.
  1698. # Remove $SUFFIX variable seen on debian that is computed
  1699. # dynamically, but is usually empty.
  1700. foreach my $k (keys %def) {
  1701. $def{$k} =~ s/\$SUFFIX//g;
  1702. push(@rv, $k."=".$def{$k});
  1703. }
  1704. }
  1705. }
  1706. foreach my $md (split(/\t+/, $config{'defines_mods'})) {
  1707. # Add HAVE_ defines from modules
  1708. opendir(DIR, $md);
  1709. while(my $m = readdir(DIR)) {
  1710. if ($m =~ /^(mod_|lib)(.*).so$/i) {
  1711. push(@rv, "HAVE_".uc($2));
  1712. }
  1713. }
  1714. closedir(DIR);
  1715. }
  1716. foreach my $d (split(/\s+/, $config{'defines'})) {
  1717. push(@rv, $d);
  1718. }
  1719. @get_httpd_defines_cache = @rv;
  1720. return @rv;
  1721. }
  1722. # create_webfile_link(file)
  1723. # Creates a link in the debian-style link directory for a new website's file
  1724. sub create_webfile_link
  1725. {
  1726. local ($file) = @_;
  1727. if ($config{'link_dir'}) {
  1728. local $short = $file;
  1729. $short =~ s/^.*\///;
  1730. local $linksrc = "$config{'link_dir'}/$short";
  1731. &lock_file($linksrc);
  1732. symlink($file, $linksrc);
  1733. &unlock_file($linksrc);
  1734. }
  1735. }
  1736. # delete_webfile_link(file)
  1737. # If the given path is in a directory like /etc/apache2/sites-available, delete
  1738. # the link to it from /etc/apache2/sites-enabled
  1739. sub delete_webfile_link
  1740. {
  1741. local ($file) = @_;
  1742. if ($config{'link_dir'}) {
  1743. local $short = $file;
  1744. $short =~ s/^.*\///;
  1745. opendir(LINKDIR, $config{'link_dir'});
  1746. foreach my $f (readdir(LINKDIR)) {
  1747. if ($f ne "." && $f ne ".." &&
  1748. (&resolve_links($config{'link_dir'}."/".$f) eq $file ||
  1749. $short eq $f)) {
  1750. &unlink_logged($config{'link_dir'}."/".$f);
  1751. }
  1752. }
  1753. closedir(LINKDIR);
  1754. }
  1755. }
  1756. # can_configure_apache_modules()
  1757. # Returns 1 if the distro has a way of selecting enabled Apache modules
  1758. sub can_configure_apache_modules
  1759. {
  1760. if ($gconfig{'os_type'} eq 'debian-linux') {
  1761. # Debian and Ubuntu use an /etc/apacheN/mods-enabled dir
  1762. return -d "$config{'httpd_dir'}/mods-enabled" &&
  1763. -d "$config{'httpd_dir'}/mods-available";
  1764. }
  1765. else {
  1766. return 0;
  1767. }
  1768. }
  1769. # list_configured_apache_modules()
  1770. # Returns a list of all Apache modules. Each is a hash containing a mod and
  1771. # enabled, disabled and available flags.
  1772. sub list_configured_apache_modules
  1773. {
  1774. if ($gconfig{'os_type'} eq 'debian-linux') {
  1775. # Find enabled modules
  1776. local @rv;
  1777. local $edir = "$config{'httpd_dir'}/mods-enabled";
  1778. opendir(EDIR, $edir);
  1779. foreach my $f (readdir(EDIR)) {
  1780. if ($f =~ /^(\S+)\.load$/) {
  1781. push(@rv, { 'mod' => $1, 'enabled' => 1 });
  1782. }
  1783. }
  1784. closedir(EDIR);
  1785. # Add available m…

Large files files are truncated, but you can click here to view the full file