Compare commits
197 Commits
dev/check-
...
9d95b5c977
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9d95b5c977 | ||
|
|
d9c651d06d | ||
|
|
c70bae48aa | ||
|
|
83abdc8858 | ||
|
|
2833450b48 | ||
|
|
a0c023637f | ||
|
|
6721e13a6b | ||
|
|
2b2814fdf4 | ||
|
|
4dacdc31f6 | ||
|
|
2627ba289e | ||
|
|
b4a67a0d90 | ||
|
|
63af275296 | ||
|
|
5f1bbc4ac2 | ||
|
|
124147205f | ||
|
|
e9b3ed9624 | ||
|
|
ccde77c0e2 | ||
|
|
ffd8171e18 | ||
|
|
65ab502176 | ||
|
|
013aa5a5c6 | ||
|
|
12dca80535 | ||
|
|
89ee635de3 | ||
|
|
af3ddd652f | ||
|
|
e6d214b776 | ||
|
|
45521e9c30 | ||
|
|
123beb03d8 | ||
|
|
72b122dbce | ||
|
|
e9be9b1d53 | ||
|
|
7beeea2106 | ||
|
|
27c5ad998e | ||
|
|
474ca81d4a | ||
|
|
a63c92f77c | ||
|
|
db96a9fd09 | ||
|
|
198cc1c4d8 | ||
|
|
4f681a2db0 | ||
|
|
ab46ec806f | ||
|
|
b1fe988f57 | ||
|
|
94c0826499 | ||
|
|
191d8a255c | ||
|
|
d4ab826097 | ||
|
|
a84c2af1d8 | ||
|
|
476915850a | ||
|
|
2510b985b1 | ||
|
|
db4f5b5e9c | ||
|
|
f3dda46138 | ||
|
|
7a278ad894 | ||
|
|
179d36859a | ||
|
|
eec14b6c1f | ||
|
|
bc44562637 | ||
|
|
a55a9e142b | ||
|
|
7911eaeae1 | ||
|
|
a2cb8daaee | ||
|
|
c4dc034da7 | ||
|
|
8a8d1bc12f | ||
|
|
025ab50ecb | ||
|
|
1f71aebe49 | ||
|
|
03379b0052 | ||
|
|
86a27eff18 | ||
|
|
b338875039 | ||
|
|
e88d16a888 | ||
|
|
f0486443ae | ||
|
|
f55515fdb0 | ||
|
|
ebefe283fd | ||
|
|
d7c49a51c7 | ||
|
|
018ad0062b | ||
|
|
50075dd71d | ||
|
|
f4e573278d | ||
|
|
9bce05f48a | ||
|
|
238756902b | ||
|
|
b597bfb0bd | ||
|
|
00adb84d69 | ||
|
|
0cf0af85cd | ||
|
|
ae89844754 | ||
|
|
9ba627e461 | ||
|
|
bae6e39889 | ||
|
|
5377098de3 | ||
|
|
48291845b4 | ||
|
|
36194ade8e | ||
|
|
d8e9ad116a | ||
|
|
4c5911887c | ||
|
|
392d3aceff | ||
|
|
15a3c91f9d | ||
|
|
58c6d41295 | ||
|
|
7b9bca5b67 | ||
|
|
ba47e2a0d0 | ||
|
|
3b06c4dccb | ||
|
|
1e6611ade5 | ||
|
|
dfa5ac8b21 | ||
|
|
d7cf050d71 | ||
|
|
7945a9f0e6 | ||
|
|
6cd04c131c | ||
|
|
9f4a4fadf7 | ||
|
|
70c7ddf3bb | ||
|
|
17764483dc | ||
|
|
cdc1c82e83 | ||
|
|
d29e5aea99 | ||
|
|
c3a2396986 | ||
|
|
da37f364dd | ||
|
|
0342f06fc8 | ||
|
|
ef05252413 | ||
|
|
74f879dc2b | ||
|
|
94cbabea9e | ||
|
|
2634afb859 | ||
|
|
4bf296447e | ||
|
|
cf458db765 | ||
|
|
af7cb99298 | ||
|
|
3d300b5fb6 | ||
|
|
8ff9b75953 | ||
|
|
06f75db35f | ||
|
|
4f851d71b1 | ||
|
|
2133d5d4bf | ||
|
|
42e5d45232 | ||
|
|
3e0a08b7ef | ||
|
|
f2f40f1227 | ||
|
|
0955695a15 | ||
|
|
fb3dd9f43d | ||
|
|
9f82fdc808 | ||
|
|
573f3d894a | ||
|
|
ff9348c056 | ||
|
|
2051bfe6dc | ||
|
|
42e228103b | ||
|
|
29d100e8eb | ||
|
|
4e4234c87e | ||
|
|
6d9aa69cb2 | ||
|
|
dbc83bae55 | ||
|
|
d37b790492 | ||
|
|
34616c5fbd | ||
|
|
c57651cd46 | ||
|
|
79f91c1468 | ||
|
|
f49f86dc96 | ||
|
|
ef1e9bbf93 | ||
|
|
84348e3fc4 | ||
|
|
1a52bf4d72 | ||
|
|
d8a74cd275 | ||
|
|
225def99ec | ||
|
|
1c9e8b5a25 | ||
|
|
e0e5ef65f8 | ||
|
|
5d67cdb7c1 | ||
|
|
c7538bc5be | ||
|
|
7959bedfe4 | ||
|
|
4c6511f2c1 | ||
|
|
42c8b02b3b | ||
|
|
fd25d65afe | ||
|
|
ae684ff02c | ||
|
|
37f1b52391 | ||
|
|
067b3e59b0 | ||
|
|
8e0c6ffb14 | ||
|
|
34a2cdd75d | ||
|
|
25b3f95d9c | ||
|
|
5d8196fe95 | ||
|
|
7f93d6ddd8 | ||
|
|
5ed06227a8 | ||
|
|
0576b027c0 | ||
|
|
31e2f533f6 | ||
|
|
51eef83562 | ||
|
|
efcfd3d20e | ||
|
|
4857976e26 | ||
|
|
3633469b4e | ||
|
|
f9373eacc2 | ||
|
|
5ed99dd7eb | ||
|
|
e7cf393f85 | ||
|
|
f5c158ef6a | ||
|
|
5b71274aa1 | ||
|
|
410cdbd01b | ||
|
|
34263aae1f | ||
|
|
3f8f9539a2 | ||
|
|
cb5f4e9d39 | ||
|
|
2acfc37745 | ||
|
|
ffe844d03d | ||
|
|
12edb92b6a | ||
|
|
8517ee6653 | ||
|
|
447727ae68 | ||
|
|
28ea58af07 | ||
|
|
48c5fc2138 | ||
|
|
b9e3363a68 | ||
|
|
f0f4f72d73 | ||
|
|
9a493e581e | ||
|
|
360236d68b | ||
|
|
7e5007e050 | ||
|
|
dfbf446092 | ||
|
|
178c6198f2 | ||
|
|
198e395833 | ||
|
|
4443982256 | ||
|
|
8866833130 | ||
|
|
b1d407a52d | ||
|
|
a7478ac4c9 | ||
|
|
8957333dca | ||
|
|
1caf80bbc1 | ||
|
|
18c12c7f8b | ||
|
|
78a3ab924d | ||
|
|
652f2db774 | ||
|
|
8b58d7cce3 | ||
|
|
52f87286a4 | ||
|
|
28c7939636 | ||
|
|
face8319f2 | ||
|
|
7a651027bf | ||
|
|
bbf317803a | ||
|
|
1091434ff4 |
9
.github/workflows/webmin.dev+webmin.yml
vendored
@@ -6,21 +6,22 @@ on:
|
||||
- master
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
- prereleased
|
||||
- released
|
||||
|
||||
jobs:
|
||||
build:
|
||||
uses: webmin/webmin-ci-cd/.github/workflows/master-workflow.yml@main
|
||||
with:
|
||||
build-type: package
|
||||
project-name: webmin
|
||||
project-name: ${{ github.event.repository.name }}
|
||||
is-release: ${{ github.event_name == 'release' }}
|
||||
is-prerelease: ${{ github.event.release.prerelease || false }}
|
||||
secrets:
|
||||
DEV_GPG_PH: ${{ secrets.DEV_GPG_PH }}
|
||||
DEV_IP_ADDR: ${{ secrets.DEV_IP_ADDR }}
|
||||
DEV_IP_KNOWN_HOSTS: ${{ secrets.DEV_IP_KNOWN_HOSTS }}
|
||||
DEV_UPLOAD_SSH_USER: ${{ secrets.DEV_UPLOAD_SSH_USER }}
|
||||
DEV_UPLOAD_SSH_DIR: ${{ secrets.DEV_UPLOAD_SSH_DIR }}
|
||||
PRERELEASE_UPLOAD_SSH_DIR: ${{ secrets.PRERELEASE_UPLOAD_SSH_DIR }}
|
||||
DEV_SSH_PRV_KEY: ${{ secrets.DEV_SSH_PRV_KEY }}
|
||||
DEV_SIGN_BUILD_REPOS_CMD: ${{ secrets.DEV_SIGN_BUILD_REPOS_CMD }}
|
||||
ALL_GPG_PH2: ${{ secrets.ALL_GPG_PH2 }}
|
||||
|
||||
69
CHANGELOG.md
@@ -1,20 +1,69 @@
|
||||
## Changelog
|
||||
|
||||
#### 2.520 (October 2, 2025)
|
||||
#### 2.621 (January 25, 2026)
|
||||
* Fix to prevent NAT from dropping idle RPC sessions during long transfers
|
||||
* Fix MySQL/MariaDB module to correctly check the version when plugins became available
|
||||
|
||||
#### 2.620 (January 9, 2026)
|
||||
* Add ability to use correct driver depending on the database in MySQL/MariaDB module
|
||||
* Add improvements to BIND DNS module for better key management
|
||||
* Add support for Ubuntu 26.04 development preview
|
||||
* Add a config option to increase the RPC timeout
|
||||
* Add support for EC SSL certificate and key in the ProFTPd module
|
||||
* Add support for using `gpart` in FreeBSD disk management module
|
||||
* Add support for Ed25519 public key in User and Groups module
|
||||
* Fix RPC session timeout during large file transfers
|
||||
* Fix selection and configuration of TLS certificate and key in the ProFTPd module
|
||||
* Update Authentic theme to the latest version with various improvements and fixes:
|
||||
* Add support for multiple scrollable tabs in the File Manager
|
||||
* Fix displaying of the right-side toolbar in File Manager when using Safari
|
||||
* Fix to print menu separator when no virtual servers are added yet in Virtualmin
|
||||
* Fix bugs in white palette
|
||||
* Fix exported file name in data tables
|
||||
|
||||
#### 2.610 (November 23, 2025)
|
||||
* Fix to drop dependency on `IO::Pty` Perl module
|
||||
* Fix `virtual-server` module server-side search to work correctly
|
||||
* Update the Authentic theme to the latest version with various improvements and fixes:
|
||||
- Add a range slider to adjust content page margins more precisely
|
||||
- Add an option to enable rounded corners for content page
|
||||
- Add more customization options for pie charts
|
||||
- Fix to increase clickable area for checkboxes in File Manager
|
||||
- Fix to correct rotation of pin and unpin button for right side slider
|
||||
- Fix color of selected items in the multiselect dropdown
|
||||
- Fix to improve the visibility of disabled checkboxes
|
||||
- Fix to send saved params in the post body when saving theme configuration
|
||||
[More details...](https://github.com/webmin/authentic-theme/releases/tag/26.20)
|
||||
|
||||
#### 2.600 (November 9, 2025)
|
||||
* Add an options to enable the slow query log in the MySQL/MariaDB module [#2560](https://github.com/webmin/webmin/issues/2560)
|
||||
* Add ability to install multiple PHP extensions at once in the PHP Configuration module
|
||||
* Add ability to show package URL in the Software Packages module [#1141](https://github.com/virtualmin/virtualmin-gpl/issues/1141)
|
||||
* Add support to show Debian package install time in the Software Packages module
|
||||
* Add support to show detailed Webmin server stats using new `webmin stats` CLI command [forum.virtualmin.com/t/135556](https://forum.virtualmin.com/t/is-this-memory-used-a-bit-high/135556/6?u=ilia)
|
||||
* Add a major Authentic theme UI update with lots of visual and structural improvements for a smoother and more modern experience
|
||||
[More details...](https://forum.virtualmin.com/t/authentic-theme-version-26-00-release-overview/135755?u=ilia)
|
||||
* Fix EOL library fatal error for OS in development [#2121](https://github.com/webmin/webmin/issues/2121)
|
||||
* Fix correctly saving jails with parameters containing quotes in the Fail2Ban module [#2572](https://github.com/webmin/webmin/issues/2572)
|
||||
* Fix file is always renamed as the effective user in the Upload and Download module [#1054](https://github.com/webmin/webmin/issues/1054)
|
||||
|
||||
#### 2.520 (October 4, 2025)
|
||||
* Fix to make sure the mail URL uses a well-known host name [security]
|
||||
* Fix support for other Raspberry Pi sensors #2545
|
||||
* Fix support for other Raspberry Pi sensors [#2545](https://github.com/webmin/webmin/issues/2545)
|
||||
* Fix the printing of the bottom button row in the form column table
|
||||
* Fix to recommend Perl `Sys::Syslog` module #2557
|
||||
* Fix to recommend Perl `Sys::Syslog` module [#2557](https://github.com/webmin/webmin/issues/2557)
|
||||
* Fix to avoid using short hostname in HTTPS redirects when an FQDN is available
|
||||
* Fix to use _/proc_ sampler instead of `vmstat` for the same output with much lower overhead
|
||||
* Fix to query specific fields in FreeBSD memory stats collection, cutting CPU use by 80%
|
||||
* Fix to kill Webmin subprocesses during RC stop on FreeBSD and other systems
|
||||
* Fix to correctly fetch command version in `PPTP VPN Client` module [#2567](https://github.com/webmin/webmin/issues/2567)
|
||||
* Add a complete overhaul of `var_dump` subroutine, which is now fully portable
|
||||
* Update the Authentic theme to the latest version with various fixes:
|
||||
- Fix the text color when reading email in the Read User Mail module [webmin#2555](https://github.com/webmin/webmin/issues/2555)
|
||||
- Fix to ensure the selected color palette is correctly stored when changed manually [webmin#2552](https://github.com/webmin/webmin/issues/2552)
|
||||
- Fix a bug when the Webmin version label was missing when copying to clipboard system information from the dashboard
|
||||
- Fix DNS query spike from network stats collection on FreeBSD [webmin#2556](https://github.com/webmin/webmin/issues/2556)
|
||||
- Fix to display the appropriate icon for proxy mode on new Bunny DNS
|
||||
- Fix spinner color in toast messages for dark palette
|
||||
- Fix other bugs and add various small improvements
|
||||
|
||||
@@ -242,7 +291,7 @@
|
||||
* Fix to using the `qrencode` command to generate QR codes locally instead of the remote Google Chart API
|
||||
* Fix a number of various other issues
|
||||
|
||||
#### 2.105 (November 09, 2023)
|
||||
#### 2.105 (November 9, 2023)
|
||||
* Fix param to read only headers [sourceforge.net/usermin-bugs#501](https://sourceforge.net/p/webadmin/usermin-bugs/501/)
|
||||
* Fix not to set `reuse` flag on initial Let's Encrypt request
|
||||
* Fix to correctly escape mail file names upon deletion
|
||||
@@ -257,7 +306,7 @@
|
||||
* Fix the absent init script for legacy systems after the initial installation
|
||||
* Update the Authentic theme to the latest version with various fixes and improvements
|
||||
|
||||
#### 2.103 (October 08, 2023)
|
||||
#### 2.103 (October 8, 2023)
|
||||
* Add support for hostname detection using `hostnamectl` command
|
||||
* Add support for other ACME services
|
||||
* Add ability to hide dotfiles in File Manager [#1578](https://github.com/webmin/authentic-theme/issues/1578)
|
||||
@@ -306,7 +355,7 @@
|
||||
* Fix clearing packages caches before checking for updates in status collection #1863
|
||||
* Update the Authentic theme to the latest version
|
||||
|
||||
#### 2.020 (March 08, 2023)
|
||||
#### 2.020 (March 8, 2023)
|
||||
* Add full locale support
|
||||
* Add slave zone file format option in BIND DNS module
|
||||
* Add support for editing ACLs in File Manager
|
||||
@@ -476,10 +525,10 @@ This release updates the built-in Let's Encrypt client, adds support for creatin
|
||||
#### Version 1.930 (August 18, 2019)
|
||||
These updates fix a [security vulnerability](http://webmin.com/security.html) and should be installed IMMEDIATELY by all users. Although it is not exploitable in a Webmin install with the default configuration, upgrading is strongly recommended.
|
||||
|
||||
#### Version 1.920 (July 04, 2019)
|
||||
#### Version 1.920 (July 4, 2019)
|
||||
This update includes the latest theme version, translation updates, the ability to disable hosts file entries, easier monitoring of bootup actions, and a bunch of bugfixes.
|
||||
|
||||
#### Version 1.910 (May 09, 2019)
|
||||
#### Version 1.910 (May 9, 2019)
|
||||
This release includes theme and translation updates, a page for editing package repositories, cron and status module improvements, and a bunch of other bugfixes and small improvements.
|
||||
|
||||
#### Version 1.900 (November 19, 2018)
|
||||
@@ -491,7 +540,7 @@ This version includes Ubuntu 18 network config support, translation updates, mul
|
||||
#### Version 1.880 (March 16, 2018)
|
||||
This version includes German, Catalan and Bulgarian translation updates, a new version of the Authentic theme, support for directly editing the MySQL and PostgreSQL config files, Let's Encrypt bugfixes, more control over system status email notifications, and more.
|
||||
|
||||
#### Version 1.870 (December 08, 2018)
|
||||
#### Version 1.870 (December 8, 2018)
|
||||
This release includes many translation updates, fixes for Let's Encrypt support, UI cleanups, and most importantly a new major version of the Authentic theme.
|
||||
|
||||
#### Version 1.860 (October 10, 2017)
|
||||
@@ -500,7 +549,7 @@ This release includes Let's Encrypt DNS fixes, Majordomo module improvements, XS
|
||||
#### Version 1.850 (June 28, 2017)
|
||||
This release includes Let's Encrypt fixes, Majordomo module improvements, FirewallD forwarding support, translation updates, an update to the Authentic theme, and a bunch of other bugfixes.
|
||||
|
||||
#### Version 1.840 (May 08, 2017)
|
||||
#### Version 1.840 (May 8, 2017)
|
||||
This major release includes a large theme update, XSS security fixes, per-domain SSL cert support, thin-provisioned LVM support, Let's Encrypt improvements, translation updates, and the usual gang of bugfixes. Also available is Usermin 1.710, which contains many of the same updates.
|
||||
|
||||
#### Version 1.830 (December 29, 2016)
|
||||
|
||||
@@ -19,11 +19,11 @@
|
||||
**Webmin** is a web-based system administration tool for Unix-like servers, and services with about _1,000,000_ yearly installations worldwide. Using it, it is possible to configure operating system internals, such as users, disk quotas, services or configuration files, as well as modify, and control open-source apps, such as BIND DNS Server, Apache HTTP Server, PHP, MySQL, and many more.
|
||||
|
||||
<p align="center">
|
||||
<a href="https://webmin.com/screenshots/#gh-light-mode-only" target="_blank">
|
||||
<img width="1440" alt="Dashboard screenshot" src="https://user-images.githubusercontent.com/4426533/218264253-c08fb45a-8d75-44bf-93b3-37a2ecae3d20.png">
|
||||
<a href="https://webmin.com/screenshots/?theme=light#gh-light-mode-only" target="_blank">
|
||||
<img width="1440" alt="Dashboard screenshot" src="https://github.com/user-attachments/assets/a01d0a78-4130-4665-9284-814955ae1c97">
|
||||
</a>
|
||||
<a href="https://webmin.com/screenshots/#gh-dark-mode-only" target="_blank">
|
||||
<img width="1440" alt="Dashboard screenshot" src="https://user-images.githubusercontent.com/4426533/218265232-31140aa6-ada1-4019-bd75-04240aeabc83.png">
|
||||
<a href="https://webmin.com/screenshots/?theme=dark#gh-dark-mode-only" target="_blank">
|
||||
<img width="1440" alt="Dashboard screenshot" src="https://github.com/user-attachments/assets/da4b90a0-c002-4e10-8b34-5acb251bbec9">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
|
||||
249
SECURITY.md
@@ -1,23 +1,242 @@
|
||||
## Reporting Security Issues
|
||||
|
||||
Please send all reports of security issues found in Webmin to security@webmin.com
|
||||
via email, ideally PGP encrypted with the key from https://www.webmin.com/jcameron-key.asc .
|
||||
> [!WARNING]
|
||||
> **Found a bug?** If you’ve found a new security-related issue, email
|
||||
> [security@webmin.com](mailto:security@webmin.com).
|
||||
|
||||
Potential security issues, in descending order of impact, include :
|
||||
### Webmin 2.510 and below [October 9, 2025]
|
||||
#### Host header injection vulnerability in the password reset feature [CVE-2025-61541]
|
||||
|
||||
* Remotely exploitable attacks that allow `root` access to Webmin without
|
||||
any credentials.
|
||||
- If the password reset feature is enabled, an attacker can use a specially
|
||||
crafted host header to cause the password reset email to contain a link to a
|
||||
malicious site.
|
||||
|
||||
* Privilege escalation vulnerabilities that allow non-`root` users of Webmin
|
||||
to run commands or access files as `root`.
|
||||
> Thanks to Nyein Chan Aung and Mg Demon for reporting this.
|
||||
|
||||
* XSS attacks that target users already logged into Webmin when they visit
|
||||
another website.
|
||||
### Webmin 2.202 and below [February 26, 2025]
|
||||
#### SSL certificates from clients may be trusted unexpectedly
|
||||
|
||||
Things that are not actually security issues include :
|
||||
- If Webmin is configured to trust remote IP addresses provided by a proxy *and*
|
||||
you have users authenticating using client SSL certificates, a browser
|
||||
connecting directly (not via the proxy) can provide a forged header to fake
|
||||
the client certificate.
|
||||
|
||||
* XSS attacks that are blocked by Webmin's referrer checks, which are enabled
|
||||
by default.
|
||||
- Upgrade to Webmin 2.301 or later, and if there is any chance of direct
|
||||
requests by clients disable this at **Webmin ⇾ Webmin Configuration ⇾ IP
|
||||
Access Control** page using **Trust level for proxy headers** option.
|
||||
|
||||
* Attacks that require modifications to Webmin's code or configuration, which
|
||||
can only be done by someone who already has `root` permissions.
|
||||
> Thanks to Keigo YAMAZAKI from LAC Co., Ltd. for reporting this.
|
||||
|
||||
### Webmin 2.105 and below [April 15, 2024]
|
||||
#### Privilege escalation by non-root users [CVE-2024-12828]
|
||||
|
||||
- A less-privileged Webmin user can execute commands as root via a vulnerability in the shell autocomplete feature.
|
||||
|
||||
- All Virtualmin admins and Webmin admins who have created additional accounts should upgrade to version 2.111 as soon as possible!
|
||||
|
||||
> Thanks to Trend Micro’s Zero Day Initiative for finding and reporting this issue.
|
||||
|
||||
### Webmin 1.995 and Usermin 1.850 and below [June 30, 2022]
|
||||
#### XSS vulnerability in the HTTP Tunnel module
|
||||
|
||||
- If a less-privileged Webmin user is given permission to edit the configuration of the HTTP Tunnel module, he/she could use this to introduce a vulnerability that captures cookies belonging to other Webmin users that use the module.
|
||||
|
||||
> Thanks to [BLACK MENACE][2] and [PYBRO][3] for reporting this issue.
|
||||
|
||||
- An HTML email crafted by an attacker could capture browser cookies when opened.
|
||||
|
||||
> Thanks to [ly1g3][4] for reporting this bug.
|
||||
|
||||
### Webmin 1.991 and below [April 18, 2022]
|
||||
#### Privilege escalation exploit [CVE-2022-30708]
|
||||
- Less privileged Webmin users (excluding those created by Virtualmin and Cloudmin) can modify arbitrary files with root privileges, and so run commands as root. All systems with additional untrusted Webmin users should upgrade immediately.
|
||||
|
||||
> Thanks to [esp0xdeadbeef][5] and [V1s3r1on][6] for finding and reporting this issue!
|
||||
|
||||
### Webmin 1.984 and below [December 26, 2021]
|
||||
#### File Manager privilege exploit [CVE-2022-0824 and CVE-2022-0829]
|
||||
|
||||
- Less privileged Webmin users who do not have any File Manager module restrictions configured can access files with root privileges, if using the default Authentic theme. All systems with additional untrusted Webmin users should upgrade immediately. Note that Virtualmin systems are not effected by this bug, due to the way domain owner Webmin users are configured.
|
||||
|
||||
> Thanks to Faisal Fs ([faisalfs10x][7]) from [NetbyteSEC][8] for finding and reporting this issue!
|
||||
|
||||
### Virtualmin Procmail wrapper version 1.0
|
||||
#### Privilege escalation exploit
|
||||
- Version 1.0 of the `procmail-wrapper` package installed with Virtualmin has a vulnerability that can be used by anyone with SSH access to gain `root` privileges. To prevent this, all Virtualmin users should upgrade to version 1.1 or later immediately.
|
||||
|
||||
### Webmin 1.973 and below [March 7, 2021]
|
||||
#### XSS vulnerabilities if Webmin is installed using the `setup.pl` script [CVE-2021-31760, CVE-2021-31761 and CVE-2021-31762]
|
||||
|
||||
- If Webmin is installed using the non-recommended `setup.pl` script, checking for unknown referers is not enabled by default. This opens the system up to XSS and CSRF attacks using malicious links. Fortunately the standard `rpm`, `deb`, `pkg` and `tar` packages do not use this script and so are not vulnerable. If you did install using the `setup.pl` script, the vulnerability can be fixed by adding the line `referers_none=1` to `/etc/webmin/config` file.
|
||||
|
||||
> Thanks to Meshal ( Mesh3l\_911 ) [@Mesh3l\_911][9] and Mohammed ( Z0ldyck ) [@electronicbots][10] for finding and reporting this issue!
|
||||
|
||||
### Webmin 1.941 and below [January 16, 2020]
|
||||
#### XSS vulnerability in the Command Shell module [CVE-2020-8820 and CVE-2020-8821]
|
||||
|
||||
- A user with privileges to create custom commands could exploit other users via unescaped HTML.
|
||||
|
||||
> Thanks to Mauro Caseres for reporting this and the following issue.
|
||||
|
||||
### Webmin 1.941 and below [January 16, 2020]
|
||||
#### XSS vulnerability in the Read Mail module [CVE-2020-12670]
|
||||
- Saving a malicious HTML attachment could trigger and XSS vulnerability.
|
||||
|
||||
### Webmin 1.882 to 1.921 [July 6, 2019]
|
||||
#### Remote Command Execution [CVE-2019-15231]
|
||||
- Webmin releases between these versions contain a vulnerability that allows remote command execution! Version 1.890 is vulnerable in a default install and should be upgraded immediately - other versions are only vulnerable if changing of expired passwords is enabled, which is not the case by default.
|
||||
|
||||
Either way, upgrading to version 1.930 is strongly recommended. Alternately, if running versions 1.900 to 1.920, edit `/etc/webmin/miniserv.conf`, remove the `passwd_mode=` line, then run `/etc/webmin/restart` command.
|
||||
{{< details-start post-indent-details "More details.." >}}
|
||||
Webmin version 1.890 was released with a backdoor that could allow anyone with knowledge of it to execute commands as root. Versions 1.900 to 1.920 also contained a backdoor using similar code, but it was not exploitable in a default Webmin install. Only if the admin had enabled the feature at **Webmin ⇾ Webmin Configuration ⇾ Authentication** to allow changing of expired passwords could it be used by an attacker.
|
||||
|
||||
Neither of these were accidental bugs - rather, the Webmin source code had been maliciously modified to add a non-obvious vulnerability. It appears that this happened as follows :
|
||||
|
||||
- At some time in April 2018, the Webmin development build server was exploited and a vulnerability added to the `password_change.cgi` script. Because the timestamp on the file was set back, it did not show up in any Git diffs. This was included in the Webmin 1.890 release.
|
||||
- The vulnerable file was reverted to the checked-in version from GitHub, but sometime in July 2018 the file was modified again by the attacker. However, this time the exploit was added to code that is only executed if changing of expired passwords is enabled. This was included in the Webmin 1.900 release.
|
||||
- On September 10th 2018, the vulnerable build server was decommissioned and replaced with a newly installed server running CentOS 7. However, the build directory containing the modified file was copied across from backups made on the original server.
|
||||
- On August 17th 2019, we were informed that a 0-day exploit that made use of the vulnerability had been released. In response, the exploit code was removed and Webmin version 1.930 created and released to all users.
|
||||
|
||||
In order to prevent similar attacks in future, we're doing the following :
|
||||
|
||||
- Updating the build process to use only checked-in code from GitHub, rather than a local directory that is kept in sync.
|
||||
- Rotated all passwords and keys accessible from the old build system.
|
||||
- Auditing all GitHub commits over the past year to look for commits that may have introduced similar vulnerabilities.
|
||||
{{< details-end >}}
|
||||
|
||||
### Webmin 1.900 [November 19, 2018]
|
||||
#### Remote Command Execution (Metasploit)
|
||||
|
||||
- This is _not_ a workable exploit as it requires that the attacker already know the root password. Hence there is no fix for it in Webmin.
|
||||
|
||||
### Webmin 1.900 and below [November 19, 2018]
|
||||
#### Malicious HTTP headers in downloaded URLs
|
||||
|
||||
- If the Upload and Download or File Manager module is used to fetch an un-trusted URL. If a Webmin user downloads a file from a malicious URL, HTTP headers returned can be used exploit an XSS vulnerability.
|
||||
|
||||
> Thanks to independent security researcher, John Page aka hyp3rlinx, who reported this vulnerability to Beyond Security's SecuriTeam Secure Disclosure program.
|
||||
|
||||
### Webmin 1.800 and below [May 26, 2016]
|
||||
#### Authentic theme configuration page vulnerability
|
||||
- Only an issue if your system has un-trusted users with Webmin access and is using the new Authentic theme. A non-root Webmin user could use the theme configuration page to execute commands as root.
|
||||
|
||||
#### Authentic theme remote access vulnerability
|
||||
- Only if the Authentic theme is enabled globally. An attacker could execute commands remotely as root, as long as there was no firewall blocking access to Webmin's port 10000.
|
||||
|
||||
### Webmin 1.750 and below [May 12, 2015]
|
||||
#### XSS (cross-site scripting) vulnerability in `xmlrpc.cgi` script [CVE-2015-1990]
|
||||
- A malicious website could create links or JavaScript referencing the `xmlrpc.cgi` script, triggered when a user logged into Webmin visits the attacking site.
|
||||
|
||||
> Thanks to Peter Allor from IBM for finding and reporting this issue.
|
||||
|
||||
### Webmin 1.720 and below [November 24, 2014]
|
||||
#### Read Mail module vulnerable to malicious links
|
||||
- If un-trusted users have both SSH access and the ability to use Read User Mail module (as is the case for Virtualmin domain owners), a malicious link could be created to allow reading any file on the system, even those owned by _root_.
|
||||
|
||||
> Thanks to Patrick William from RACK911 labs for finding this bug.
|
||||
|
||||
### Webmin 1.700 and below [August 11, 2014]
|
||||
#### Shellshock vulnerability
|
||||
- If your _bash_ shell is vulnerable to _shellshock_, it can be exploited by attackers who have a Webmin login to run arbitrary commands as _root_. Updating to version 1.710 (or updating _bash_) will fix this issue.
|
||||
|
||||
### Webmin 1.590 and below [June 30, 2012]
|
||||
#### XSS (cross-site scripting) security hole
|
||||
- A malicious website could create links or JavaScript referencing the File Manager module that allowed execution of arbitrary commands via Webmin when the website is viewed by the victim. See [CERT vulnerability note VU#788478][12] for more details. Thanks to Jared Allar from the American Information Security Group for reporting this problem.
|
||||
|
||||
#### Referer checks don't include port
|
||||
- If an attacker has control over `http://example.com/` then he/she could create a page with malicious JavaScript that could take over a Webmin session at `https://example.com:10000/` when `http://example.com/` is viewed by the victim.
|
||||
|
||||
> Thanks to Marcin Teodorczyk for finding this issue.
|
||||
|
||||
### Webmin 1.540 and below [April 20, 2011]
|
||||
#### XSS (cross-site scripting) security hole
|
||||
- This vulnerability can be triggered if an attacker changes his Unix username via a tool like `chfn`, and a page listing usernames is then viewed by the root user in Webmin.
|
||||
|
||||
> Thanks to Javier Bassi for reporting this bug.
|
||||
|
||||
### Virtualmin 3.70 and below [June 23, 2009]
|
||||
#### Unsafe file writes in Virtualmin
|
||||
- This bug allows a virtual server owner to read or write to arbitrary files on the system by creating malicious symbolic links and then having Virtualmin perform operations on those links. Upgrading to version 3.70 is strongly recommended if your system has un-trusted domain owners.
|
||||
|
||||
### Webmin 1.390 and below, Usermin 1.320 and below [February 8, 2008]
|
||||
#### XSS (cross-site scripting) security hole
|
||||
- This attack could open users who visit un-trusted websites while having Webmin open in the same browser up to having their session cookie captured, which could then allow an attacker to login to Webmin without a password. The quick fix is to go to the **Webmin Configuration** module, click on the **Trusted Referers** icon, set **Referrer checking enabled?** to **Yes**, and un-check the box **Trust links from unknown referrers**. Webmin 1.400 and Usermin 1.330 will make these settings the defaults.
|
||||
|
||||
### Webmin 1.380 and below [November 3, 2007]
|
||||
#### Windows-only command execution bug
|
||||
- Any user logged into Webmin can execute any command using special URL parameters. This could be used by less-privileged Webmin users to raise their level of access.
|
||||
|
||||
> Thanks for Keigo Yamazaki of Little eArth Corporation for finding this bug.
|
||||
|
||||
### Webmin 1.374 and below, Usermin 1.277 and below
|
||||
#### XSS bug in `pam_login.cgi` script
|
||||
- A malicious link to Webmin `pam_login.cgi` script can be used to execute JavaScript within the Webmin server context, and perhaps steal session cookies.
|
||||
|
||||
### Webmin 1.330 and below, Usermin 1.260 and below
|
||||
#### XSS bug in `chooser.cgi` script
|
||||
- When using Webmin or Usermin to browse files on a system that were created by an attacker, a specially crafted filename could be used to inject arbitrary JavaScript into the browser.
|
||||
|
||||
### Webmin 1.296 and below, Usermin 1.226 and below
|
||||
#### Remote source code access
|
||||
- An attacker can view the source code of Webmin CGI and Perl programs using a specially crafted URL. Because the source code for Webmin is freely available, this issue should only be of concern to sites that have custom modules for which they want the source to remain hidden.
|
||||
#### XSS bug
|
||||
- The XSS bug makes use of a similar technique to craft a URL that can allow arbitrary JavaScript to be executed in the user's browser if a malicious link is clicked on.
|
||||
|
||||
> Thanks for Keigo Yamazaki of Little eArth Corporation for finding this bug.
|
||||
|
||||
### Webmin 1.290 and below, Usermin 1.220 and below
|
||||
#### Arbitrary remote file access
|
||||
- An attacker without a login to Webmin can read the contents of any file on the server using a specially crafted URL. All users should upgrade to version 1.290 as soon as possible, or setup IP access control in Webmin.
|
||||
|
||||
> Thanks to Kenny Chen for bringing this to my attention.
|
||||
|
||||
### Webmin 1.280 and below
|
||||
#### Windows arbitrary file access
|
||||
- If running Webmin on Windows, an attacker can remotely view the contents of any file on your system using a specially crafted URL. This does not affect other operating systems, but if you use Webmin on Windows you should upgrade to version 1.280 or later.
|
||||
|
||||
> Thanks to Keigo Yamazaki of Little eArth Corporation for discovering this bug.
|
||||
|
||||
### Webmin 1.250 and below, Usermin 1.180 and below
|
||||
#### Perl syslog input attack
|
||||
- When logging of failing login attempts via `syslog` is enabled, an attacker can crash and possibly take over the Webmin webserver, due to un-checked input being passed to Perl's `syslog` function. Upgrading to the latest release of Webmin is recommended.
|
||||
|
||||
> Thanks to Jack at Dyad Security for reporting this problem to me.
|
||||
|
||||
### Webmin 1.220 and below, Usermin 1.150 and below
|
||||
#### Full PAM conversations' mode remote attack
|
||||
- Affects systems when the option **Support full PAM conversations?** is enabled on the **Webmin ⇾ Webmin Configuration ⇾ Authentication** page. When this option is enabled in Webmin or Usermin, an attacker can gain remote access to Webmin without needing to supply a valid login or password. Fortunately this option is not enabled by default and is rarely used unless you have a PAM setup that requires more than just a username and password, but upgrading is advised anyway. <br />
|
||||
|
||||
> Thanks to Keigo Yamazaki of Little eArth Corporation and [JPCERT/CC][13] for discovering and notifying me of this bug.
|
||||
|
||||
### Webmin 1.175 and below, Usermin 1.104 and below
|
||||
#### Brute force password guessing attack
|
||||
- Prior Webmin and Usermin versions do not have password timeouts turned on by default, so an attacker can try every possible password for the _root_ or admin user until he/she finds the correct one.
|
||||
The solution is to enable password timeouts, so that repeated attempts to login as the same user will become progressively slower. This can be done by following these steps :
|
||||
|
||||
* Go to the **Webmin Configuration** module.
|
||||
* Click on the **Authentication** icon.
|
||||
* Select the **Enable password timeouts** button.
|
||||
* Click the **Save** button at the bottom of the page.
|
||||
|
||||
This problem is also present in Usermin, and can be prevented by following the same steps in the **Usermin Configuration** module.
|
||||
|
||||
### Webmin 1.150 and below, Usermin 1.080 and below
|
||||
#### XSS vulnerability
|
||||
- When viewing HTML email, several potentially dangerous types of URLs can be passed through. This can be used to perform malicious actions like executing commands as the logged-in Usermin user.
|
||||
|
||||
#### Module configurations are visible
|
||||
- Even if a Webmin user does not have access to a module, he/she can still view it's Module Config page by entering a URL that calls `config.cgi` with the module name as a parameter.
|
||||
|
||||
#### Account lockout attack
|
||||
- By sending a specially constructed password, an attacker can lock out other users if password timeouts are enabled.
|
||||
|
||||
[2]: https://github.com/bl4ckmenace
|
||||
[3]: https://github.com/Pybro09
|
||||
[4]: https://github.com/ly1g3
|
||||
[5]: https://github.com/esp0xdeadbeef
|
||||
[6]: https://github.com/V1s3r1on
|
||||
[7]: https://github.com/faisalfs10x/
|
||||
[8]: https://www.netbytesec.com/
|
||||
[9]: https://twitter.com/Mesh3l_911
|
||||
[10]: https://twitter.com/electronicbots
|
||||
[12]: http://www.kb.cert.org/vuls/id/788478
|
||||
[13]: http://www.jpcert.or.jp/
|
||||
|
||||
@@ -82,7 +82,7 @@ print &ui_table_row($text{'unix_restrict2'},
|
||||
print &ui_table_row("",
|
||||
&ui_checkbox("shells_deny", 1, $text{'unix_shells'},
|
||||
$miniserv{'shells_deny'} ? 1 : 0)." ".
|
||||
&ui_filebox("shells", $miniserv{'shells_deny'} || "/etc/shells", 40));
|
||||
&ui_filebox("shells", $miniserv{'shells_deny'} || "/etc/shells", 25));
|
||||
|
||||
print &ui_table_end();
|
||||
print &ui_form_end([ [ undef, $text{'save'} ] ]);
|
||||
|
||||
@@ -238,6 +238,18 @@ my @themes = grep { !$_->{'overlay'} } @all;
|
||||
my @overlays = grep { $_->{'overlay'} } @all;
|
||||
|
||||
if ($access{'theme'}) {
|
||||
my $tconf_link;
|
||||
my %tinfo = &webmin::get_theme_info($user{'theme'});
|
||||
if ($user{'theme'} && $user{'theme'} eq $tinfo{'dir'} &&
|
||||
$user{'name'} eq $remote_user &&
|
||||
$tinfo{'config_link'}) {
|
||||
$tconf_link = &ui_tag('span', &ui_link(
|
||||
"@{[&get_webprefix()]}/$tinfo{'config_link'}",
|
||||
&ui_tag('span', '⚙',
|
||||
{ class => 'theme-config-char',
|
||||
title => $text{'themes_configure'} }),
|
||||
'text-link'), { style => 'position: relative;' });
|
||||
}
|
||||
# Current theme
|
||||
my @topts = ( );
|
||||
push(@topts, !$user{'theme'} ? [ '', $text{'edit_themedef'} ] : ());
|
||||
@@ -247,7 +259,8 @@ if ($access{'theme'}) {
|
||||
print &ui_table_row($text{'edit_theme'},
|
||||
&ui_radio("theme_def", defined($user{'theme'}) ? 0 : 1,
|
||||
[ [ 1, $text{'edit_themeglobal'} ],
|
||||
[ 0, &ui_select("theme", $user{'theme'}, \@topts) ] ]));
|
||||
[ 0, &ui_select("theme", $user{'theme'}, \@topts).
|
||||
$tconf_link ] ]));
|
||||
}
|
||||
|
||||
if ($access{'theme'} && @overlays) {
|
||||
|
||||
@@ -7,7 +7,7 @@ use warnings;
|
||||
no warnings 'redefine';
|
||||
no warnings 'uninitialized';
|
||||
require './acl-lib.pl';
|
||||
our (%in, %text, %config, %access, $base_remote_user);
|
||||
our (%in, %text, %config, %gconfig, %access, $base_remote_user);
|
||||
&ReadParse();
|
||||
&ui_print_header(undef, $text{'index_title'}, "", undef, 1, 1);
|
||||
|
||||
@@ -206,7 +206,7 @@ if (uc($ENV{'HTTPS'}) eq "ON" && $miniserv{'ca'}) {
|
||||
push(@icons, "images/twofactor.gif");
|
||||
push(@links, "twofactor_form.cgi");
|
||||
push(@titles, $text{'index_twofactor'});
|
||||
if ($access{'rbacenable'}) {
|
||||
if ($access{'rbacenable'} && $gconfig{'os_type'} eq 'solaris') {
|
||||
push(@icons, "images/rbac.gif");
|
||||
push(@links, "edit_rbac.cgi");
|
||||
push(@titles, $text{'index_rbac'});
|
||||
@@ -291,7 +291,13 @@ return &ui_checkbox("d", $user->{'name'}, "", 0).
|
||||
($ro ? "<b>" : "").
|
||||
&ui_link("$cgi?$param=".&urlize($user->{'name'}),
|
||||
$user->{'name'}).
|
||||
($user->{'twofactor_id'} ? "*" : "").
|
||||
($user->{'twofactor_id'}
|
||||
? &ui_tag('sup', '⚷',
|
||||
{ title => $text{'index_twofactor_enabled'},
|
||||
class => 'twofactor-enabled-icon',
|
||||
style => 'font-size: 11px; margin-left: 5px; cursor: default;'.
|
||||
'display: inline-block; transform: rotate(90deg);' } )
|
||||
: "").
|
||||
($ro ? "</b>" : "").
|
||||
($lck ? "</i>" : "");
|
||||
}
|
||||
|
||||
11
acl/lang/en
@@ -6,6 +6,7 @@ index_screate=Create a new safe user.
|
||||
index_convert=Convert Unix To Webmin Users
|
||||
index_cert=Request an SSL Certificate
|
||||
index_twofactor=Two-Factor Authentication
|
||||
index_twofactor_enabled=Two-factor authentication is enabled for this user
|
||||
index_certmsg=Click this button to request an SSL certificate that will allow you to securely login to Webmin without having to enter a username and password.
|
||||
index_return=user list
|
||||
index_none=None
|
||||
@@ -358,16 +359,16 @@ sessions_user=Webmin user
|
||||
sessions_login_ago=Last active ago
|
||||
sessions_login=Last active at
|
||||
sessions_host=IP address
|
||||
sessions_lview=View logs..
|
||||
sessions_actions=Actions..
|
||||
sessions_all=All sessions..
|
||||
sessions_logouts=Also show logged-out sessions..
|
||||
sessions_lview=View logs
|
||||
sessions_actions=Actions
|
||||
sessions_all=All sessions
|
||||
sessions_logouts=Also show logged-out sessions
|
||||
sessions_state=State
|
||||
sessions_action=Actions
|
||||
sessions_this=This login
|
||||
sessions_in=Logged in
|
||||
sessions_out=Logged out
|
||||
sessions_kill=Disconnect..
|
||||
sessions_kill=Disconnect
|
||||
|
||||
logins_title=Recent Webmin logins
|
||||
|
||||
|
||||
@@ -1235,6 +1235,9 @@ sub restart_button
|
||||
local $args = "redir=".&urlize(&this_url());
|
||||
local @rv;
|
||||
if (&is_apache_running()) {
|
||||
if ($access{'stop'}) {
|
||||
push(@rv, &ui_link("stop.cgi?$args", $text{'apache_stop'}) );
|
||||
}
|
||||
if ($access{'apply'}) {
|
||||
my $n = &needs_config_restart();
|
||||
if ($n) {
|
||||
@@ -1245,9 +1248,6 @@ if (&is_apache_running()) {
|
||||
push(@rv, &ui_link("restart.cgi?$args", $text{'apache_apply'}) );
|
||||
}
|
||||
}
|
||||
if ($access{'stop'}) {
|
||||
push(@rv, &ui_link("stop.cgi?$args", $text{'apache_stop'}) );
|
||||
}
|
||||
}
|
||||
elsif ($access{'stop'}) {
|
||||
push(@rv, &ui_link("start.cgi?$args", $text{'apache_start'}) );
|
||||
|
||||
@@ -161,6 +161,7 @@ manual_efile=Invalid Apache config file
|
||||
manual_etest=Configuration file error detected : $1
|
||||
manual_editfile=Edit config file:
|
||||
manual_switch=Edit
|
||||
manual_evirt=Virtual host could not be found after manual changes - maybe the ServerName was changed?
|
||||
|
||||
dir_title=Per-Directory Options
|
||||
dir_proxyall=All proxy requests
|
||||
|
||||
@@ -73,6 +73,14 @@ if ($config{'test_manual'}) {
|
||||
&error(&text('manual_etest',
|
||||
"<pre>".&html_escape($err)."</pre>"));
|
||||
}
|
||||
if (defined($in{'virt'}) && !defined($in{'idx'})) {
|
||||
undef(@get_config_cache);
|
||||
($conf, $v) = &get_virtual_config($in{'virt'});
|
||||
if (!$v) {
|
||||
©_source_dest($temp, $file);
|
||||
&error($text{'manual_evirt'});
|
||||
}
|
||||
}
|
||||
}
|
||||
unlink($temp);
|
||||
&unlock_file($file);
|
||||
|
||||
@@ -158,7 +158,7 @@ $rv .= "<table id='show_backup_destination' cellpadding=1 cellspacing=0>";
|
||||
|
||||
# Local file field
|
||||
$rv .= "<tr><td>".&ui_oneradio("$_[0]_mode", 0, undef, $mode == 0)."</td>\n";
|
||||
$rv .= "<td>$text{'backup_mode0'} </td><td colspan='3'>".
|
||||
$rv .= "<td>".&ui_tag('strong', $text{'backup_mode0'})." </td><td colspan='3'>".
|
||||
&ui_textbox("$_[0]_file", $mode == 0 ? $path : "", 60, undef, undef,
|
||||
($_[2] != 1 && $config{'date_subs'}) ?
|
||||
'placeholder="/backups/configs-%y-%m-%d-%H-%M-%S.tar.gz"' : undef).
|
||||
@@ -166,7 +166,7 @@ $rv .= "<td>$text{'backup_mode0'} </td><td colspan='3'>".
|
||||
|
||||
# FTP file fields
|
||||
$rv .= "<tr><td>".&ui_oneradio("$_[0]_mode", 1, undef, $mode == 1)."</td>\n";
|
||||
$rv .= "<td>$text{'backup_mode1'} </td><td>".
|
||||
$rv .= "<td>".&ui_tag('strong', $text{'backup_mode1'})." </td><td>".
|
||||
&ui_textbox("$_[0]_server", $mode == 1 ? $server : undef, 20).
|
||||
"</td>\n";
|
||||
$rv .= "<td> $text{'backup_path'} </td><td> ".
|
||||
@@ -186,7 +186,7 @@ $rv .= "<td colspan='4'>$text{'backup_port'} ".
|
||||
|
||||
# SCP file fields
|
||||
$rv .= "<tr><td>".&ui_oneradio("$_[0]_mode", 2, undef, $mode == 2)."</td>\n";
|
||||
$rv .= "<td>$text{'backup_mode2'} </td><td>".
|
||||
$rv .= "<td>".&ui_tag('strong', $text{'backup_mode2'})." </td><td>".
|
||||
&ui_textbox("$_[0]_sserver", $mode == 2 ? $server : undef, 20).
|
||||
"</td>\n";
|
||||
$rv .= "<td> $text{'backup_path'} </td><td> ".
|
||||
@@ -208,7 +208,7 @@ if ($_[2] == 1) {
|
||||
# Uploaded file field
|
||||
$rv .= "<tr><td>".&ui_oneradio("$_[0]_mode", 3, undef, $mode == 3).
|
||||
"</td>\n";
|
||||
$rv .= "<td colspan=4>$text{'backup_mode3'} ".
|
||||
$rv .= "<td colspan=4>".&ui_tag('strong', $text{'backup_mode3'})." ".
|
||||
&ui_upload("$_[0]_upload", 40).
|
||||
"</td> </tr>\n";
|
||||
}
|
||||
@@ -216,7 +216,8 @@ elsif ($_[2] == 2) {
|
||||
# Output to browser option
|
||||
$rv .= "<tr><td>".&ui_oneradio("$_[0]_mode", 4, undef, $mode == 4).
|
||||
"</td>\n";
|
||||
$rv .= "<td colspan=4>$text{'backup_mode4'}</td> </tr>\n";
|
||||
$rv .= "<td colspan=4>".&ui_tag('strong', $text{'backup_mode4'}).
|
||||
"</td> </tr>\n";
|
||||
}
|
||||
|
||||
$rv .= "</table>\n";
|
||||
|
||||
@@ -5,7 +5,7 @@ use strict;
|
||||
use warnings;
|
||||
no warnings 'redefine';
|
||||
no warnings 'uninitialized';
|
||||
our (%text, %config, $no_acl_check);
|
||||
our (%text, %config, $no_acl_check, %gconfig);
|
||||
$no_acl_check++;
|
||||
require './backup-config-lib.pl';
|
||||
&foreign_require("mailboxes", "mailboxes-lib.pl");
|
||||
@@ -76,11 +76,10 @@ if (($err || $backup->{'emode'} == 0) && $backup->{'email'}) {
|
||||
$postmsg;
|
||||
$subject = &text('email_sok', $host);
|
||||
}
|
||||
&mailboxes::send_text_mail($config{'from_addr'} ||
|
||||
&mailboxes::get_from_address(),
|
||||
$backup->{'email'},
|
||||
undef,
|
||||
$subject,
|
||||
$msg);
|
||||
&mailboxes::send_text_mail(
|
||||
$config{'from_addr'} || &mailboxes::get_from_address(),
|
||||
$backup->{'email'} eq '*' ? $gconfig{'webmin_email_to'}
|
||||
: $backup->{'email'},
|
||||
undef, $subject, $msg);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,10 +10,11 @@ our (%in, %text, %gconfig);
|
||||
&ReadParse();
|
||||
|
||||
my $backup;
|
||||
my $wet = $gconfig{'webmin_email_to'};
|
||||
if ($in{'new'}) {
|
||||
&ui_print_header(undef, $text{'edit_title1'}, "");
|
||||
$backup = { 'emode' => 0,
|
||||
'email' => $gconfig{'webmin_email_to'},
|
||||
'email' => $wet ? '*' : undef,
|
||||
'sched' => 1,
|
||||
'configfile' => 1,
|
||||
'nofiles' => 0,
|
||||
@@ -74,7 +75,10 @@ print &ui_hidden_table_start($text{'edit_header3'}, "width=100%", 2,
|
||||
|
||||
# Show email address
|
||||
print &ui_table_row($text{'edit_email'},
|
||||
&ui_textbox("email", $backup->{'email'}, 40));
|
||||
$wet ? &ui_opt_textbox("email",
|
||||
$backup->{'email'} eq '*' ? undef : $backup->{'email'},
|
||||
40, &text('edit_email_def', "<tt>$wet</tt>"))
|
||||
: &ui_textbox("email", $backup->{'email'}, 40));
|
||||
|
||||
# Show email mode
|
||||
print &ui_table_row($text{'edit_emode'},
|
||||
|
||||
@@ -30,7 +30,7 @@ my $using_strftime = 0;
|
||||
if (@backups) {
|
||||
# Show all scheduled backups
|
||||
print &ui_link("edit.cgi?new=1", $text{'index_add'});
|
||||
print "<br>\n";
|
||||
print "<br>\n";
|
||||
print &ui_columns_start([ $text{'index_dest'},
|
||||
$text{'index_mods'},
|
||||
$text{'index_sched'} ], 100);
|
||||
|
||||
@@ -27,6 +27,7 @@ edit_header=Scheduled backup options
|
||||
edit_header2=Pre and post backup commands
|
||||
edit_header3=Backup schedule
|
||||
edit_email=Email result to address
|
||||
edit_email_def=Webmin default ($1)
|
||||
edit_emode=When to send email
|
||||
edit_emode0=Always
|
||||
edit_emode1=Only when an error occurs
|
||||
|
||||
@@ -36,7 +36,7 @@ else {
|
||||
$backup->{'dest'} = &parse_backup_destination("dest", \%in);
|
||||
&cron::parse_times_input($backup, \%in);
|
||||
$backup->{'emode'} = $in{'emode'};
|
||||
$backup->{'email'} = $in{'email'};
|
||||
$backup->{'email'} = $in{'email_def'} ? '*' : $in{'email'};
|
||||
$backup->{'pre'} = $in{'pre'};
|
||||
$backup->{'post'} = $in{'post'};
|
||||
$backup->{'sched'} = $in{'sched'};
|
||||
|
||||
391
bin/server
@@ -22,7 +22,7 @@ sub main
|
||||
# If username passed as regular param
|
||||
my $cmd = scalar(@ARGV) == 1 && $ARGV[0];
|
||||
$cmd = $opt{'command'} if ($opt{'command'});
|
||||
if ($cmd !~ /^(status|start|stop|restart|reload|force-restart|kill)$/) {
|
||||
if ($cmd !~ /^(stats|status|start|stop|restart|reload|force-restart|kill)$/) {
|
||||
$cmd = undef;
|
||||
}
|
||||
|
||||
@@ -92,6 +92,395 @@ sub run
|
||||
}
|
||||
exit $rs;
|
||||
}
|
||||
if ($o->{'cmd'} =~ /^(stats)$/) {
|
||||
my $rs = 0;
|
||||
if (-x $systemctlcmd) {
|
||||
my $format_bytes = sub {
|
||||
my $bytes = shift;
|
||||
return "0" unless defined $bytes && $bytes =~ /^\d+$/;
|
||||
|
||||
my $mb = $bytes / 1048576;
|
||||
my $gb = $mb / 1024;
|
||||
|
||||
if ($gb >= 1) {
|
||||
return sprintf("%.2f GB", $gb);
|
||||
} elsif ($mb >= 1) {
|
||||
return sprintf("%.2f MB", $mb);
|
||||
} else {
|
||||
return sprintf("%.2f KB", $bytes / 1024);
|
||||
}
|
||||
};
|
||||
|
||||
# Check if service is running first
|
||||
my $is_active_cmd = qq{systemctl is-active "$service" 2>/dev/null};
|
||||
my $is_active = `$is_active_cmd`;
|
||||
$rs = $? >> 8;
|
||||
chomp($is_active);
|
||||
|
||||
if ($rs != 0 || $is_active ne 'active') {
|
||||
print "Service '$service' is not running (status: $is_active)\n";
|
||||
return 2;
|
||||
}
|
||||
|
||||
# Get main pid
|
||||
my $main_pid_cmd = qq{systemctl show -p MainPID --value "$service"};
|
||||
my $main_pid = `$main_pid_cmd`;
|
||||
$rs = $? >> 8;
|
||||
return $rs if $rs != 0;
|
||||
chomp($main_pid);
|
||||
|
||||
if (!$main_pid || $main_pid eq '0') {
|
||||
print "Service '$service' has no main PID\n";
|
||||
return;
|
||||
}
|
||||
|
||||
# Get process list
|
||||
my $cmd = qq{
|
||||
CG=\$(systemctl show -p ControlGroup --value "$service");
|
||||
P=\$({ cat /sys/fs/cgroup"\$CG"/cgroup.procs; systemctl show -p MainPID --value "$service"; } | sort -u);
|
||||
COLUMNS=10000 ps --cols 10000 -ww --no-headers -o pid=,ppid=,rss=,pmem=,pcpu=,args= --sort=-rss -p \$P |
|
||||
awk 'function h(k){m=k/1024;g=m/1024;return g>=1?sprintf("%.2fG",g):sprintf("%.1fM",m)} BEGIN{printf "%6s %6s %9s %6s %6s %-s\\n","PID","PPID","RSS_KiB","%MEM","%CPU","CMD (RSS_human)"} {cmd=substr(\$0,index(\$0,\$6)); printf "%6s %6s %9s %6s %6s %s (%s)\\n",\$1,\$2,\$3,\$4,\$5,cmd,h(\$3)}'
|
||||
};
|
||||
my $out = `$cmd`;
|
||||
$rs = $? >> 8;
|
||||
return $rs if $rs != 0;
|
||||
|
||||
# Extract pids from the output
|
||||
my @all_pids;
|
||||
foreach my $line (split(/\n/, $out)) {
|
||||
if ($line =~ /^\s*(\d+)\s+/) {
|
||||
push @all_pids, $1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!@all_pids) {
|
||||
print "No processes found for service '$service'\n";
|
||||
return 3;
|
||||
}
|
||||
|
||||
# Reorder with main pid first, then rest sorted by size
|
||||
my @pids;
|
||||
if ($main_pid && $main_pid ne '' && grep { $_ eq $main_pid } @all_pids) {
|
||||
push @pids, $main_pid;
|
||||
push @pids, grep { $_ ne $main_pid } @all_pids;
|
||||
} else {
|
||||
@pids = @all_pids;
|
||||
}
|
||||
|
||||
# Print the table with main pid marked
|
||||
foreach my $line (split(/\n/, $out)) {
|
||||
if ($line =~ /^\s*$main_pid\s+/ && $main_pid) {
|
||||
chomp($line);
|
||||
print "$line [MAIN]\n";
|
||||
} else {
|
||||
print "$line\n";
|
||||
}
|
||||
}
|
||||
|
||||
# Check if lsof is available
|
||||
my $has_lsof = has_command('lsof');
|
||||
|
||||
# Get detailed info for each pid
|
||||
foreach my $pid (@pids) {
|
||||
my $is_main = ($pid eq $main_pid) ? " [MAIN PROCESS]" : "";
|
||||
|
||||
# Check if process still exists
|
||||
unless (-d "/proc/$pid") {
|
||||
print "\n\nProcess $pid no longer exists, skipping...\n";
|
||||
next;
|
||||
}
|
||||
|
||||
print "\n";
|
||||
print "╔" . "═"x78 . "╗\n";
|
||||
print "║" . sprintf("%-78s", " DETAILED ANALYSIS FOR PID $pid$is_main") . "║\n";
|
||||
print "╚" . "═"x78 . "╝\n";
|
||||
|
||||
# Working directory and binary
|
||||
print "\n┌─ WORKING DIRECTORY & BINARY " . "─"x49 . "\n";
|
||||
my $cwd = `readlink /proc/$pid/cwd 2>/dev/null`;
|
||||
chomp($cwd);
|
||||
print "CWD: $cwd\n" if $cwd;
|
||||
|
||||
my $exe = `readlink /proc/$pid/exe 2>/dev/null`;
|
||||
chomp($exe);
|
||||
print "EXE: $exe\n" if $exe;
|
||||
|
||||
my $root = `readlink /proc/$pid/root 2>/dev/null`;
|
||||
chomp($root);
|
||||
print "ROOT: $root\n" if $root && $root ne '/';
|
||||
|
||||
# Environment variables
|
||||
print "\n┌─ ENVIRONMENT VARIABLES " . "─"x54 . "\n";
|
||||
my $env = `cat /proc/$pid/environ 2>/dev/null | tr '\\0' '\\n' | grep -E '^(PATH|HOME|USER|LANG|TZ|LD_|PYTHON|JAVA|NODE|PORT|HOST|DB_|API_)' | sort`;
|
||||
if ($env) {
|
||||
print $env;
|
||||
} else {
|
||||
print "Unable to read environment\n";
|
||||
}
|
||||
|
||||
# Basic process info
|
||||
print "\n┌─ PROCESS INFO " . "─"x63 . "\n";
|
||||
my $ps_info = `ps -p $pid -o user=,pid=,ppid=,pri=,ni=,vsz=,rss=,stat=,start=,time=,cmd= 2>/dev/null`;
|
||||
if ($ps_info) {
|
||||
print "USER PID PPID PRI NI VSZ RSS STAT START TIME CMD\n";
|
||||
print $ps_info;
|
||||
} else {
|
||||
print "Process no longer exists\n";
|
||||
next;
|
||||
}
|
||||
|
||||
# Process tree
|
||||
print "\n┌─ PROCESS TREE " . "─"x63 . "\n";
|
||||
my $pstree = `pstree -p -a $pid 2>/dev/null`;
|
||||
if ($pstree) {
|
||||
print $pstree;
|
||||
} else {
|
||||
print "pstree not available\n";
|
||||
}
|
||||
|
||||
# Memory and status
|
||||
print "\n┌─ MEMORY & STATUS " . "─"x60 . "\n";
|
||||
my $status = `grep -E 'VmPeak|VmSize|VmRSS|VmSwap|RssAnon|RssFile|Threads|voluntary_ctxt|nonvoluntary_ctxt' /proc/$pid/status 2>/dev/null`;
|
||||
print $status || "N/A\n";
|
||||
|
||||
# Open file descriptors
|
||||
print "\n┌─ FILE DESCRIPTORS " . "─"x59 . "\n";
|
||||
my $fd_count = `ls -1 /proc/$pid/fd 2>/dev/null | wc -l`;
|
||||
chomp($fd_count);
|
||||
print "Total Open FDs: $fd_count\n";
|
||||
|
||||
if ($has_lsof) {
|
||||
print "\nFile Descriptor Types:\n";
|
||||
my $fd_types = `lsof +c 0 -p $pid 2>/dev/null | awk 'NR>1 {print \$5}' | sort | uniq -c | sort -rn`;
|
||||
print $fd_types || "Unable to get FD types\n";
|
||||
|
||||
print "\nDetailed File Descriptors:\n";
|
||||
my $all_fds = `lsof +c 0 -p $pid 2>/dev/null`;
|
||||
$all_fds =~ s/^/ /mg;
|
||||
print $all_fds || "No files open\n";
|
||||
} else {
|
||||
print "\n(Install lsof for detailed file descriptor analysis)\n";
|
||||
print "\nOpen FD Sample:\n";
|
||||
my $fd_sample = `ls -la /proc/$pid/fd 2>/dev/null | head -15`;
|
||||
print $fd_sample;
|
||||
}
|
||||
|
||||
# Network Connections
|
||||
print "\n┌─ NETWORK CONNECTIONS " . "─"x56 . "\n";
|
||||
|
||||
# tcp connections with details
|
||||
my $tcp_detailed = `ss -tnp -o 2>/dev/null | grep 'pid=$pid'`;
|
||||
my $tcp_count = `echo "$tcp_detailed" | grep -c 'pid=$pid'` || 0;
|
||||
chomp($tcp_count);
|
||||
print "Active TCP Connections: $tcp_count\n";
|
||||
|
||||
if ($tcp_count > 0) {
|
||||
print "\nTCP Connections (with timers and queues):\n";
|
||||
print $tcp_detailed;
|
||||
|
||||
print "\nConnection State Summary:\n";
|
||||
my $state_summary = `ss -tnp 2>/dev/null | grep 'pid=$pid' | awk '{print \$1}' | sort | uniq -c | sort -rn`;
|
||||
print $state_summary;
|
||||
|
||||
print "\nLocal Ports in Use:\n";
|
||||
my $local_ports = `ss -tnp 2>/dev/null | grep 'pid=$pid' | awk '{split(\$4,a,":"); print a[length(a)]}' | sort -n | uniq -c`;
|
||||
print $local_ports || "None\n";
|
||||
|
||||
print "\nRemote Endpoints:\n";
|
||||
my $remote_ips = `ss -tnp 2>/dev/null | grep 'pid=$pid' | awk '{print \$5}' | cut -d: -f1 | sort | uniq -c | sort -rn`;
|
||||
print $remote_ips || "None\n";
|
||||
}
|
||||
|
||||
# tcp listening
|
||||
my $tcp_listen = `ss -tlnp 2>/dev/null | grep 'pid=$pid'`;
|
||||
if ($tcp_listen) {
|
||||
print "\nTCP Listening Sockets:\n";
|
||||
print $tcp_listen;
|
||||
}
|
||||
|
||||
# udp connections
|
||||
my $udp_count = `ss -unp 2>/dev/null | grep -c 'pid=$pid'`;
|
||||
chomp($udp_count);
|
||||
if ($udp_count > 0) {
|
||||
print "\nUDP Connections: $udp_count\n";
|
||||
my $udp_conns = `ss -unp 2>/dev/null | grep 'pid=$pid'`;
|
||||
print $udp_conns;
|
||||
}
|
||||
|
||||
# udp listening
|
||||
my $udp_listen = `ss -ulnp 2>/dev/null | grep 'pid=$pid'`;
|
||||
if ($udp_listen) {
|
||||
print "\nUDP Listening Sockets:\n";
|
||||
print $udp_listen;
|
||||
}
|
||||
|
||||
# unix sockets
|
||||
my $unix_sockets = `ss -xp 2>/dev/null | grep 'pid=$pid' | wc -l`;
|
||||
chomp($unix_sockets);
|
||||
if ($unix_sockets > 0) {
|
||||
print "\nUnix Domain Sockets: $unix_sockets\n";
|
||||
}
|
||||
|
||||
# I/O Statistics
|
||||
print "\n┌─ I/O STATISTICS " . "─"x61 . "\n";
|
||||
my $io = `cat /proc/$pid/io 2>/dev/null`;
|
||||
if ($io) {
|
||||
print $io;
|
||||
# Parse and show human-readable
|
||||
my ($read_bytes, $write_bytes);
|
||||
if ($io =~ /read_bytes:\s*(\d+)/) {
|
||||
$read_bytes = $1;
|
||||
}
|
||||
if ($io =~ /write_bytes:\s*(\d+)/) {
|
||||
$write_bytes = $1;
|
||||
}
|
||||
if (defined $read_bytes && defined $write_bytes) {
|
||||
print "\nRead: " . $format_bytes->($read_bytes) .
|
||||
", Write: " . $format_bytes->($write_bytes) . "\n";
|
||||
}
|
||||
} else {
|
||||
print "N/A\n";
|
||||
}
|
||||
|
||||
# Resource Limits
|
||||
print "\n┌─ RESOURCE LIMITS " . "─"x60 . "\n";
|
||||
my $limits = `grep -E 'Max open files|Max processes|Max locked memory|Max address space|Max cpu time' /proc/$pid/limits 2>/dev/null`;
|
||||
print $limits || "N/A\n";
|
||||
|
||||
# Cgroup limits
|
||||
my $cg_path = `cat /proc/$pid/cgroup 2>/dev/null | grep '^0::' | cut -d: -f3`;
|
||||
chomp($cg_path);
|
||||
my $cgroup_output = "";
|
||||
if ($cg_path) {
|
||||
my $mem_limit = `cat /sys/fs/cgroup$cg_path/memory.max 2>/dev/null`;
|
||||
my $mem_current = `cat /sys/fs/cgroup$cg_path/memory.current 2>/dev/null`;
|
||||
my $cpu_max = `cat /sys/fs/cgroup$cg_path/cpu.max 2>/dev/null`;
|
||||
|
||||
chomp($mem_limit, $mem_current, $cpu_max);
|
||||
|
||||
if ($mem_limit && $mem_limit ne 'max') {
|
||||
$cgroup_output .= "Memory Limit: " . $format_bytes->(int($mem_limit)) . "\n";
|
||||
$cgroup_output .= "Memory Current: " . $format_bytes->(int($mem_current)) . "\n" if $mem_current;
|
||||
if ($mem_current) {
|
||||
my $pct = sprintf("%.1f", ($mem_current / $mem_limit) * 100);
|
||||
$cgroup_output .= "Memory Usage: $pct%\n";
|
||||
}
|
||||
}
|
||||
if ($cpu_max && $cpu_max ne 'max') {
|
||||
$cgroup_output .= "CPU Quota: $cpu_max\n";
|
||||
}
|
||||
}
|
||||
if ($cgroup_output) {
|
||||
print "\n┌─ CGROUP LIMITS " . "─"x62 . "\n";
|
||||
print $cgroup_output;
|
||||
}
|
||||
|
||||
# CPU & Scheduling
|
||||
print "\n┌─ CPU & SCHEDULING " . "─"x59 . "\n";
|
||||
my $sched = `grep -E 'se.sum_exec_runtime|nr_switches|nr_voluntary_switches|nr_involuntary_switches' /proc/$pid/sched 2>/dev/null | head -4`;
|
||||
if ($sched) {
|
||||
print $sched;
|
||||
}
|
||||
my $cpuset = `cat /proc/$pid/cpuset 2>/dev/null`;
|
||||
chomp($cpuset);
|
||||
print "CPUset: $cpuset\n" if $cpuset;
|
||||
|
||||
# Signal handlers
|
||||
print "\n┌─ SIGNAL HANDLERS " . "─"x60 . "\n";
|
||||
my $signals = `cat /proc/$pid/status 2>/dev/null | grep -E '^Sig(Cgt|Ign|Blk):'`;
|
||||
if ($signals) {
|
||||
print $signals;
|
||||
|
||||
# Decode signal masks
|
||||
my %signal_names = (
|
||||
1 => 'SIGHUP', 2 => 'SIGINT', 3 => 'SIGQUIT',
|
||||
4 => 'SIGILL', 5 => 'SIGTRAP', 6 => 'SIGABRT',
|
||||
7 => 'SIGBUS', 8 => 'SIGFPE', 9 => 'SIGKILL',
|
||||
10 => 'SIGUSR1', 11 => 'SIGSEGV', 12 => 'SIGUSR2',
|
||||
13 => 'SIGPIPE', 14 => 'SIGALRM', 15 => 'SIGTERM',
|
||||
16 => 'SIGSTKFLT', 17 => 'SIGCHLD', 18 => 'SIGCONT',
|
||||
19 => 'SIGSTOP', 20 => 'SIGTSTP', 21 => 'SIGTTIN',
|
||||
22 => 'SIGTTOU', 23 => 'SIGURG', 24 => 'SIGXCPU',
|
||||
25 => 'SIGXFSZ', 26 => 'SIGVTALRM', 27 => 'SIGPROF',
|
||||
28 => 'SIGWINCH', 29 => 'SIGIO', 30 => 'SIGPWR',
|
||||
31 => 'SIGSYS'
|
||||
);
|
||||
|
||||
my $decode_sigmask = sub {
|
||||
my ($hex_mask, $names_ref) = @_;
|
||||
return "none" if $hex_mask eq '0000000000000000';
|
||||
|
||||
# Convert hex to decimal
|
||||
my $mask = hex($hex_mask);
|
||||
my @signals;
|
||||
|
||||
# Check each bit
|
||||
for (my $i = 1; $i <= 31; $i++) {
|
||||
if ($mask & (1 << ($i - 1))) {
|
||||
push @signals, "$names_ref->{$i}($i)";
|
||||
}
|
||||
}
|
||||
|
||||
return @signals ? join(", ", @signals) : "none";
|
||||
};
|
||||
|
||||
print "\nDecoded:\n";
|
||||
if ($signals =~ /SigBlk:\s*([0-9a-f]+)/i) {
|
||||
print " Blocked: " .
|
||||
$decode_sigmask->($1, \%signal_names) . "\n";
|
||||
}
|
||||
if ($signals =~ /SigIgn:\s*([0-9a-f]+)/i) {
|
||||
print " Ignored: " .
|
||||
$decode_sigmask->($1, \%signal_names) . "\n";
|
||||
}
|
||||
if ($signals =~ /SigCgt:\s*([0-9a-f]+)/i) {
|
||||
print " Caught: " .
|
||||
$decode_sigmask->($1, \%signal_names) . "\n";
|
||||
}
|
||||
} else {
|
||||
print "N/A\n";
|
||||
}
|
||||
|
||||
# Memory maps sum
|
||||
print "\n┌─ MEMORY MAPS (top 20 by size) " . "─"x47 . "\n";
|
||||
my $maps = `awk '
|
||||
/^[0-9a-f]+-[0-9a-f]+/ {hdr=\$0}
|
||||
/^Size:/ {size=\$2}
|
||||
/^Rss:/ {rss=\$2}
|
||||
/^VmFlags:/ { if (rss>0) {print rss"\\t"size"\\t"hdr} rss=0; size=0 }
|
||||
' /proc/$pid/smaps 2>/dev/null | sort -rn | head -20`;
|
||||
|
||||
if ($maps) {
|
||||
print "RSS(MB)\tSize(MB)\tMapping\n";
|
||||
foreach my $map_line (split(/\n/, $maps)) {
|
||||
if ($map_line =~ /^(\d+)\s+(\d+)\s+(.+)$/) {
|
||||
my $rss_mb = sprintf("%.2f", $1 / 1024);
|
||||
my $size_mb = sprintf("%.2f", $2 / 1024);
|
||||
print "$rss_mb\t$size_mb\t\t$3\n";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
print "Unable to read memory maps\n";
|
||||
}
|
||||
|
||||
# Recent logs
|
||||
print "\n┌─ RECENT LOGS (last 20 lines) " . "─"x48 . "\n";
|
||||
my $logs = `journalctl _PID=$pid -b -n 20 --no-pager -o short-precise 2>/dev/null`;
|
||||
if ($logs && $logs !~ /^-- No entries --/) {
|
||||
print $logs;
|
||||
} else {
|
||||
print "No recent logs found for this PID in current boot\n";
|
||||
}
|
||||
|
||||
print "\n" . "─"x79 . "\n";
|
||||
}
|
||||
|
||||
} else {
|
||||
print "Stats command is only available on systemd based systems.\n";
|
||||
$rs = 1;
|
||||
}
|
||||
exit $rs;
|
||||
}
|
||||
exit 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,13 @@ use Getopt::Long qw(:config permute pass_through);
|
||||
use Term::ANSIColor qw(:constants);
|
||||
use Pod::Usage;
|
||||
|
||||
# Check if root
|
||||
if ($> != 0) {
|
||||
die BRIGHT_RED, "Error: ", RESET, BRIGHT_YELLOW,"webmin", RESET,
|
||||
" command must be run as root\n";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
my $a0 = $ARGV[0];
|
||||
|
||||
sub main {
|
||||
@@ -280,7 +287,7 @@ sub get_command_path {
|
||||
}
|
||||
}
|
||||
if ($optref->{'commands'} &&
|
||||
$optref->{'commands'} =~ /^(status|start|stop|restart|reload|force-restart|force-reload|kill)$/) {
|
||||
$optref->{'commands'} =~ /^(stats|status|start|stop|restart|reload|force-restart|force-reload|kill)$/) {
|
||||
exit system("$0 server $optref->{'commands'}");
|
||||
} elsif ($command) {
|
||||
return $command;
|
||||
|
||||
@@ -70,12 +70,18 @@ sub get_rand_flag
|
||||
if ($gconfig{'os_type'} =~ /-linux$/ &&
|
||||
$config{'force_random'} eq '0' &&
|
||||
-r "/dev/urandom" &&
|
||||
&compare_version_numbers($bind_version, 9) >= 0 &&
|
||||
&compare_version_numbers($bind_version, '9.14.2') < 0) {
|
||||
# Version: 9.14.2 deprecated the use of -r option
|
||||
# in favor of using /dev/random [bugs:#5370]
|
||||
return "-r /dev/urandom";
|
||||
&compare_version_numbers($bind_version, 9) >= 0) {
|
||||
if (&compare_version_numbers($bind_version, '9.14.2') < 0) {
|
||||
return "-r /dev/urandom";
|
||||
}
|
||||
else {
|
||||
# Version: 9.14.2 deprecated the use of -r option
|
||||
# in favor of using /dev/random [bugs:#5370]. So no
|
||||
# entropy generation is needed.
|
||||
return undef;
|
||||
}
|
||||
}
|
||||
# No random flag, and entropy is needed
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -1118,7 +1124,7 @@ else {
|
||||
@v = ( );
|
||||
}
|
||||
if ($type eq "A" || $type eq "AAAA") {
|
||||
print &ui_table_row($text{'value_A1'},
|
||||
print &ui_table_row($text{"value_${type}1"},
|
||||
&ui_textbox("value0", $v[0], 20)." ".
|
||||
(!defined($_[5]) && $type eq "A" ?
|
||||
&free_address_button("value0") : ""), 3);
|
||||
@@ -3121,11 +3127,11 @@ $slave_error = $_[0];
|
||||
|
||||
sub get_forward_record_types
|
||||
{
|
||||
return ("A", "NS", "CNAME",
|
||||
return ("A", $config{'support_aaaa'} ? ( "AAAA" ) : ( ), "NS", "CNAME",
|
||||
$config{'allow_alias'} ? ( "ALIAS" ) : ( ),
|
||||
"MX", "HINFO", "TXT", "SPF", "DMARC", "WKS", "RP", "PTR", "LOC",
|
||||
"SRV", "KEY", "TLSA", "SSHFP", "CAA", "NAPTR", "NSEC3PARAM",
|
||||
$config{'support_aaaa'} ? ( "AAAA" ) : ( ), @extra_forward);
|
||||
@extra_forward);
|
||||
}
|
||||
|
||||
sub get_reverse_record_types
|
||||
@@ -3458,7 +3464,8 @@ closedir(ZONEDIR);
|
||||
|
||||
# Fork a background job to do lots of IO, to generate entropy
|
||||
my $pid;
|
||||
if (!&get_rand_flag()) {
|
||||
my $flag = &get_rand_flag();
|
||||
if (defined($flag) && !$flag) {
|
||||
$pid = fork();
|
||||
if (!$pid) {
|
||||
exec("find / -type f >/dev/null 2>&1");
|
||||
@@ -3507,7 +3514,7 @@ else {
|
||||
"cd ".quotemeta($fn)." && ".
|
||||
"$config{'keygen'} -a ".quotemeta($alg).
|
||||
" -b ".quotemeta($zonesize).
|
||||
" -n ZONE ".&get_rand_flag()." $dom 2>&1");
|
||||
" -n ZONE ".($flag || "")." $dom 2>&1");
|
||||
if ($?) {
|
||||
kill('KILL', $pid) if ($pid);
|
||||
return $out;
|
||||
@@ -3519,7 +3526,7 @@ else {
|
||||
"cd ".quotemeta($fn)." && ".
|
||||
"$config{'keygen'} -a ".quotemeta($alg).
|
||||
" -b ".quotemeta($size).
|
||||
" -n ZONE -f KSK ".&get_rand_flag()." $dom 2>&1");
|
||||
" -n ZONE -f KSK ".($flag || "")." $dom 2>&1");
|
||||
kill('KILL', $pid) if ($pid);
|
||||
if ($?) {
|
||||
return $out;
|
||||
@@ -3589,7 +3596,8 @@ $zonekey || return "Could not find DNSSEC zone key";
|
||||
|
||||
# Fork a background job to do lots of IO, to generate entropy
|
||||
my $pid;
|
||||
if (!&get_rand_flag()) {
|
||||
my $flag = &get_rand_flag();
|
||||
if (defined($flag) && !$flag) {
|
||||
$pid = fork();
|
||||
if (!$pid) {
|
||||
exec("find / -type f >/dev/null 2>&1");
|
||||
@@ -3606,7 +3614,7 @@ my $alg = $zonekey->{'algorithm'};
|
||||
my $out = &backquote_logged(
|
||||
"cd ".quotemeta($dir)." && ".
|
||||
"$config{'keygen'} -a ".quotemeta($alg)." -b ".quotemeta($zonesize).
|
||||
" -n ZONE ".&get_rand_flag()." $dom 2>&1");
|
||||
" -n ZONE ".($flag || "")." $dom 2>&1");
|
||||
kill('KILL', $pid) if ($pid);
|
||||
if ($?) {
|
||||
return "Failed to generate new zone key : $out";
|
||||
|
||||
|
Before Width: | Height: | Size: 202 B After Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 248 B After Width: | Height: | Size: 5.9 KiB |
BIN
bind8/images/CAA.gif
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
bind8/images/NAPTR.gif
Normal file
|
After Width: | Height: | Size: 9.9 KiB |
|
Before Width: | Height: | Size: 251 B After Width: | Height: | Size: 10 KiB |
BIN
bind8/images/SSHFP.gif
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 364 B After Width: | Height: | Size: 11 KiB |
@@ -262,7 +262,7 @@ edit_upfwd=Update forward?
|
||||
edit_err=Failed to save record
|
||||
edit_egone=Selected record no longer exists!
|
||||
edit_ettl='$1' is not a valid time-to-live
|
||||
edit_eip='$1' is not a valid IP address
|
||||
edit_eip='$1' is not a valid IP4 address
|
||||
edit_eip6='$1' is not a valid IPv6 address
|
||||
edit_ehost='$1' is not a valid hostname
|
||||
edit_eserv2='$1' is not a valid service name
|
||||
@@ -309,8 +309,8 @@ edit_espfa='$1' is not a valid host to allow sending from
|
||||
edit_espfa2='$1' must be a hostname, not an IP address
|
||||
edit_espfmx='$1' is not a valid domain name to allow MX sending from
|
||||
edit_espfmxmax=You are not allowed to have more than 10 domains to allow MX sending from
|
||||
edit_espfip='$1' is not a valid IP address or IP/prefix to allow sending from
|
||||
edit_espfip6='$1' is not a valid IPv6 address or IPv6/prefix to allow sending from
|
||||
edit_espfip='$1' is not a valid IPv4 address or IPv4 prefix to allow sending from
|
||||
edit_espfip6='$1' is not a valid IPv6 address or IPv6 prefix to allow sending from
|
||||
edit_espfinclude='$1' is not a valid additional domain from which mail is sent
|
||||
edit_espfredirect='$1' is not a valid alternate domain name
|
||||
edit_espfexp='$1' is a valid record name for a rejection message
|
||||
@@ -394,7 +394,7 @@ boot_err=Download failed
|
||||
boot_egzip=The root zone file is compressed, but the <tt>gzip</tt> command is not installed on your system!
|
||||
boot_egzip2=Uncompression of root zone file failed : $1
|
||||
|
||||
type_A=Address
|
||||
type_A=IPv4 Address
|
||||
type_AAAA=IPv6 Address
|
||||
type_NS=Name Server
|
||||
type_CNAME=Name Alias
|
||||
@@ -417,7 +417,7 @@ type_KEY=Public Key
|
||||
type_CAA=Certificate Authority
|
||||
type_NAPTR=Name Authority Pointer
|
||||
|
||||
edit_A=Address
|
||||
edit_A=IPv4 Address
|
||||
edit_AAAA=IPv6 Address
|
||||
edit_NS=Name Server
|
||||
edit_CNAME=Name Alias
|
||||
@@ -440,7 +440,7 @@ edit_CAA=Certificate Authority
|
||||
edit_NAPTR=Name Authority Pointer
|
||||
|
||||
recs_defttl=Default TTL
|
||||
recs_A=Address
|
||||
recs_A=IPv4 Address
|
||||
recs_AAAA=IPv6 Address
|
||||
recs_NS=Name Server
|
||||
recs_CNAME=Name Alias
|
||||
@@ -464,7 +464,7 @@ recs_CAA=Certificate Authority
|
||||
recs_NAPTR=Name Authority
|
||||
recs_delete=Delete Selected
|
||||
|
||||
value_A1=Address
|
||||
value_A1=IPv4 Address
|
||||
value_AAAA1=IPv6 Address
|
||||
value_NS1=Name Server
|
||||
value_CNAME1=Real Name
|
||||
@@ -511,7 +511,7 @@ value_spfmx=Allow sending from domain's MX hosts?
|
||||
value_spfptr=Allow sending from any host in domain?
|
||||
value_spfas=Additional allowed sender hosts
|
||||
value_spfmxs=Additional allowed sender MX domains
|
||||
value_spfip4s=Additional allowed sender IP addresses/networks
|
||||
value_spfip4s=Additional allowed sender IPv4 addresses/networks
|
||||
value_spfip6s=Additional allowed sender IPv6 addresses/networks
|
||||
value_spfincludes=Other domains from which mail is sent
|
||||
value_spfall=Action for other senders
|
||||
|
||||
@@ -37,7 +37,7 @@ if (@tls) {
|
||||
print &ui_columns_end();
|
||||
}
|
||||
else {
|
||||
print "<b>$text{'tls_none'}</b> <p>\n";
|
||||
print &ui_alert_box($text{'tls_none'}, 'info', undef, undef, "");
|
||||
}
|
||||
print &ui_links_row(\@links);
|
||||
|
||||
|
||||
@@ -126,10 +126,11 @@ if ($access{'locale'}) {
|
||||
|
||||
if ($access{'theme'}) {
|
||||
# Show personal theme
|
||||
my %tinfo = ();
|
||||
my $tname;
|
||||
if ($gconfig{'theme'}) {
|
||||
my ($gtheme, $goverlay) = split(/\s+/, $gconfig{'theme'});
|
||||
my %tinfo = &webmin::get_theme_info($gtheme);
|
||||
%tinfo = &webmin::get_theme_info($gtheme);
|
||||
$tname = $tinfo{'desc'};
|
||||
}
|
||||
else {
|
||||
@@ -140,6 +141,16 @@ if ($access{'theme'}) {
|
||||
my @overlays = grep { $_->{'overlay'} } @all;
|
||||
|
||||
# Main theme
|
||||
my $tconf_link;
|
||||
if ($user->{'theme'} && $user->{'theme'} eq $tinfo{'dir'} &&
|
||||
$tinfo{'config_link'}) {
|
||||
$tconf_link = &ui_tag('span', &ui_link(
|
||||
"@{[&get_webprefix()]}/$tinfo{'config_link'}",
|
||||
&ui_tag('span', '⚙',
|
||||
{ class => 'theme-config-char',
|
||||
title => $text{'themes_configure'} }),
|
||||
'text-link'), { style => 'position: relative;' });
|
||||
}
|
||||
print &ui_table_row($text{'index_theme'},
|
||||
&ui_radio("theme_def", defined($user->{'theme'}) ? 0 : 1,
|
||||
[ [ 1, &text('index_themeglobal', $tname)."<br>" ],
|
||||
@@ -149,7 +160,8 @@ if ($access{'theme'}) {
|
||||
? [ '', $text{'index_themedef'} ]
|
||||
: (),
|
||||
map { [ $_->{'dir'}, $_->{'desc'} ] }
|
||||
@themes ]), undef, [ "valign=top","valign=top" ]);
|
||||
@themes ]).$tconf_link,
|
||||
undef, [ "valign=top","valign=top" ]);
|
||||
|
||||
# Overlay, if any
|
||||
if (@overlays) {
|
||||
|
||||
@@ -833,7 +833,7 @@ if ($config{'vixie_cron'} && (!$nospecial || $job->{'special'})) {
|
||||
1, 0, 0, 0, "onChange='change_special_mode(form, 1)'");
|
||||
$rv .= &ui_table_row($msg,
|
||||
&ui_radio("special_def", $job->{'special'} ? 1 : 0,
|
||||
[ [ 1, $text{'edit_special1'}." ".$specialsel ],
|
||||
[ [ 1, $text{'edit_special1'}." ".$specialsel ],
|
||||
[ 0, $text{'edit_special0'} ] ]),
|
||||
$msg ? $width-1 : $width);
|
||||
}
|
||||
@@ -924,7 +924,7 @@ foreach my $arr ("mins", "hours", "days", "months", "weekdays") {
|
||||
$table .= &ui_columns_row(\@cols, [ "valign=top", "valign=top", "valign=top",
|
||||
"valign=top", "valign=top" ]);
|
||||
$table .= &ui_columns_end();
|
||||
$table .= $text{'edit_ctrl'};
|
||||
$table .= &ui_note($text{'edit_ctrl'}, 0);
|
||||
$rv .= &ui_table_row(undef, $table, $width, undef, ['data-schedule-tr']);
|
||||
return $rv;
|
||||
}
|
||||
@@ -1056,7 +1056,8 @@ foreach $arr ("mins", "hours", "days", "months", "weekdays") {
|
||||
}
|
||||
print "</tr></table></td>\n";
|
||||
}
|
||||
print "</tr> <tr $cb> <td colspan=5>$text{'edit_ctrl'}</td> </tr>\n";
|
||||
my $ctlnote = &ui_note($text{'edit_ctrl'}, 0);
|
||||
print "</tr> <tr $cb> <td colspan=5>$ctlnote</td> </tr>\n";
|
||||
}
|
||||
|
||||
=head2 parse_times_input(&job, &in)
|
||||
|
||||
@@ -230,9 +230,9 @@ if ($in{'search'}) {
|
||||
|
||||
# Show search form
|
||||
print &ui_form_start("index.cgi");
|
||||
print "$text{'index_search'}: \n";
|
||||
print "$text{'index_search'} \n";
|
||||
print &ui_textbox("search", $in{'search'}, 20);
|
||||
print &ui_submit($text{'index_ok'});
|
||||
print &ui_submit($text{'ui_searchok'});
|
||||
print &ui_form_end();
|
||||
|
||||
# Check if we are over the display limit
|
||||
|
||||
@@ -27,7 +27,7 @@ index_enable=تمكين الوظائف المختارة
|
||||
index_esearch=لا توجد وظائف تطابق بحثك عن$1.
|
||||
index_toomany2=هناك الكثير من الوظائف لا تظهر. استخدم نموذج البحث أعلاه للحد من القائمة.
|
||||
index_search=العثور على وظائف مطابقة كرون
|
||||
index_ok=بحث
|
||||
ui_searchok=بحث
|
||||
index_searchres=وظائف Cron مطابقة$1 ..
|
||||
index_reset=إعادة ضبط البحث.
|
||||
index_econfigcheck=لا يمكن إدارة مهام Cron على نظامك ، لأن تكوين الوحدة غير صالح :$1
|
||||
|
||||
@@ -25,7 +25,7 @@ index_enable=Включи избраните задачи
|
||||
index_esearch=Няма задачи, които да съответстват на търсенето ви за $1.
|
||||
index_toomany2=Задачите са твърде много, за да бъдат показани. Използвайте системата за търсене по-горе, за да ограничите списъка.
|
||||
index_search=Открий задачи на Cron, които съответстват
|
||||
index_ok=Търсене
|
||||
ui_searchok=Търсене
|
||||
index_searchres=Задачи на Cron, които съответстват на $1 ..
|
||||
index_reset=Инициализиране на търсенето.
|
||||
index_econfigcheck=Задачите на Cron не могат да бъдат управлявани във вашата система, тъй като конфигурацията на модула не е валидна : $1
|
||||
|
||||
@@ -27,7 +27,7 @@ index_enable=Activa els Treballs Seleccionats
|
||||
index_esearch=No hi ha cap treball que coincideixi amb la recerca de $1.
|
||||
index_toomany2=Hi ha massa treballs per mostrar. Utilitza el formulari de cerca de dalt per limitar la llista.
|
||||
index_search=Busca els treballs Cron que coincideixin amb
|
||||
index_ok=Busca
|
||||
ui_searchok=Busca
|
||||
index_searchres=Treballs cron que coincideixen amb...
|
||||
index_reset=Reinici la cerca.
|
||||
index_econfigcheck=No es poden gestionar treballs Cron al sistema perquè la configuració del mòdul no és vàlida: $1
|
||||
|
||||
@@ -23,7 +23,7 @@ index_enable=Zapnout vybrané úlohy
|
||||
index_esearch=Žádné úlohy neodpovídají vyhledávací podmínce $1.
|
||||
index_toomany2=Příliš mnoho úloh k zobrazení. Použijte formulář vyhledávání k omezení jejich počtu.
|
||||
index_search=Najít úlohy Cronu odpovídající podmínce
|
||||
index_ok=Hledat
|
||||
ui_searchok=Hledat
|
||||
index_searchres=Úlohy Cronu vyhovující $1 ..
|
||||
index_reset=Resetovat hledání.
|
||||
index_econfigcheck=Úlohy Cronu nelze na Vašem systému spravovat, dokud nebude konfigurace modulu v pořádku: $1
|
||||
|
||||
@@ -27,7 +27,7 @@ index_enable=Aktivér valgte job
|
||||
index_esearch=Ingen job matchede din søgning efter $1.
|
||||
index_toomany2=Der er for mange job at vise. Brug søgeformen ovenfor til at begrænse listen.
|
||||
index_search=Find matchende Cron-job
|
||||
index_ok=Søg
|
||||
ui_searchok=Søg
|
||||
index_searchres=Cron job matchende $1 ..
|
||||
index_reset=Nulstil søgning.
|
||||
index_econfigcheck=Cron-job kan ikke administreres på dit system, da modulkonfigurationen ikke er gyldig : $1
|
||||
|
||||
@@ -27,7 +27,7 @@ index_enable=Ausgewählte Jobs aktivieren
|
||||
index_esearch=Keine Jobs entsprechen Ihrer Suche nach $1.
|
||||
index_toomany2=Es gibt zu viele Jobs, um sie anzuzeigen. Verwenden Sie das Suchformular oben, um die Liste zu begrenzen.
|
||||
index_search=Finde passende Cron-Jobs
|
||||
index_ok=Suche
|
||||
ui_searchok=Suche
|
||||
index_searchres=Cron-Jobs, die $1 entsprechen ..
|
||||
index_reset=Suche zurücksetzen.
|
||||
index_econfigcheck=Cron-Jobs können auf Ihrem System nicht verwaltet werden, da die Modulkonfiguration ungültig ist: $1
|
||||
|
||||
@@ -27,7 +27,7 @@ index_enable=Ενεργοποίηση επιλεγμένων εργασιών
|
||||
index_esearch=Καμία εργασία δεν ταιριάζει με την αναζήτησή σας για $1.
|
||||
index_toomany2=Υπάρχουν πάρα πολλές δουλειές για προβολή. Χρησιμοποιήστε τη φόρμα αναζήτησης παραπάνω για να περιορίσετε τη λίστα.
|
||||
index_search=Βρείτε τις αντιστοιχίες εργασιών Cron
|
||||
index_ok=Αναζήτηση
|
||||
ui_searchok=Αναζήτηση
|
||||
index_searchres=Οι εργασίες Cron αντιστοιχούν στο $1 ..
|
||||
index_reset=Επαναφορά αναζήτησης.
|
||||
index_econfigcheck=Δεν είναι δυνατή η διαχείριση των εργασιών Cron στο σύστημά σας, καθώς η διαμόρφωση της μονάδας δεν είναι έγκυρη : $1
|
||||
|
||||
@@ -27,7 +27,7 @@ index_enable=Enable Selected Jobs
|
||||
index_esearch=No jobs matched your search for $1.
|
||||
index_toomany2=There are too many jobs to show. Use the search form above to limit the list.
|
||||
index_search=Find Cron jobs matching
|
||||
index_ok=Search
|
||||
ui_searchok=Search
|
||||
index_searchres=Cron jobs matching $1 ..
|
||||
index_reset=Reset search.
|
||||
index_econfigcheck=Cron jobs cannot be managed on your system, as the module configuration is not valid : $1
|
||||
@@ -63,8 +63,8 @@ edit_run=Run Now
|
||||
edit_saverun=Save and Run Now
|
||||
edit_clone=Clone Job
|
||||
edit_return=cron job
|
||||
edit_ctrl=Note: Ctrl-click (or command-click on the Mac) to select and de-select minutes, hours, days and months.
|
||||
edit_special1=Simple schedule ..
|
||||
edit_ctrl=Tip: Use Ctrl-click (or ⌘-click on Mac) to select or deselect multiple items, or Shift-click to select a range
|
||||
edit_special1=Simple schedule
|
||||
edit_special0=Times and dates selected below ..
|
||||
edit_special_hourly=Hourly
|
||||
edit_special_daily=Daily (at midnight)
|
||||
|
||||
@@ -10,7 +10,7 @@ index_enable=Habilitar trabajos seleccionados
|
||||
index_esearch=Ningún trabajo coincide con su búsqueda de $1.
|
||||
index_toomany2=Hay demasiados trabajos para mostrar. Use el formulario de búsqueda anterior para limitar la lista.
|
||||
index_search=Encuentra trabajos de Cron que coincidan
|
||||
index_ok=Buscar
|
||||
ui_searchok=Buscar
|
||||
index_searchres=Cron empleos que coinciden con $1 ..
|
||||
index_reset=Restablecer búsqueda.
|
||||
index_econfigcheck=Los trabajos Cron no se pueden administrar en su sistema, ya que la configuración del módulo no es válida : $1
|
||||
|
||||
@@ -27,7 +27,7 @@ index_enable=Gaitu hautatutako lanak
|
||||
index_esearch=Ez da lanik datorren $1 bilaketarekin.
|
||||
index_toomany2=Lanpostu gehiegi daude erakusteko. Erabili goiko inprimakia zerrenda mugatzeko.
|
||||
index_search=Aurkitu Cron lanekin bat datozenak
|
||||
index_ok=Search
|
||||
ui_searchok=Search
|
||||
index_searchres=$1 datozen Cron lanak.
|
||||
index_reset=Bilaketa berrezarri.
|
||||
index_econfigcheck=Cron lanak ezin dira zure sisteman kudeatu, moduluaren konfigurazioa ez baita baliozkoa : $1
|
||||
|
||||
@@ -14,7 +14,7 @@ index_enable=مشاغل انتخاب شده را فعال کنید
|
||||
index_esearch=هیچ مشاقی با جستجوی$1 شما مطابقت ندارد.
|
||||
index_toomany2=کارهای بسیار زیادی برای نشان دادن وجود دارد. برای محدود کردن لیست از فرم جستجو در بالا استفاده کنید.
|
||||
index_search=تطبیق کار Cron را پیدا کنید
|
||||
index_ok=جستجو کردن
|
||||
ui_searchok=جستجو کردن
|
||||
index_searchres=مشاغل کرون مطابق با$1 ..
|
||||
index_reset=تنظیم مجدد جستجو
|
||||
index_econfigcheck=مشاغل Cron روی سیستم شما قابل مدیریت نیست ، زیرا پیکربندی ماژول معتبر نیست :$1
|
||||
|
||||
@@ -27,7 +27,7 @@ index_enable=Ota valitut työt käyttöön
|
||||
index_esearch=Yksikään työ ei vastannut hakutulosta $1.
|
||||
index_toomany2=Työpaikkoja on liian paljon näytettäväksi. Rajoita luetteloa yllä olevan hakulomakkeen avulla.
|
||||
index_search=Etsi sopivia Cron-töitä
|
||||
index_ok=Hae
|
||||
ui_searchok=Hae
|
||||
index_searchres=Cron-työt, jotka vastaavat $1 ..
|
||||
index_reset=Nollaa haku.
|
||||
index_econfigcheck=Cron-töitä ei voida hallita järjestelmässäsi, koska moduulin kokoonpano ei ole kelvollinen : $1
|
||||
|
||||
@@ -24,7 +24,7 @@ index_enable=Activer les tâches sélectionnées
|
||||
index_esearch=Aucune tâche ne correspond à votre recherche pour $1.
|
||||
index_toomany2=Il y a trop de tâches à montrer. Utilisez le formulaire de recherche ci-dessus pour limiter la liste.
|
||||
index_search=Trouver les tâches Cron correspondantes
|
||||
index_ok=Rechercher
|
||||
ui_searchok=Rechercher
|
||||
index_searchres=Les tâches Cron correspondent à $1 ...
|
||||
index_reset=Réinitialiser la recherche
|
||||
index_econfigcheck=Les tâches Cron ne peuvent pas être gérées sur votre système car la configuration du module n'est pas valide : $1
|
||||
|
||||
@@ -6,7 +6,7 @@ index_ecrondir_create=Pokušajte stvoriti direktorij poslova $1 ?
|
||||
index_esearch=Nijedan posao ne odgovara vašoj pretrazi za $1.
|
||||
index_toomany2=Previše je poslova za pokazati. Upotrijebite gornji obrazac za pretraživanje da biste ograničili popis.
|
||||
index_search=Pronađite Cron poslove koji se podudaraju
|
||||
index_ok=traži
|
||||
ui_searchok=traži
|
||||
index_searchres=Cron poslovi koji odgovaraju $1 ..
|
||||
index_reset=Poništi pretraživanje.
|
||||
index_econfigcheck=Cron poslovi ne mogu se upravljati u vašem sustavu, jer konfiguracija modula nije valjana : $1
|
||||
|
||||
@@ -27,7 +27,7 @@ index_enable=Kiválasztott munka engedélyezése
|
||||
index_esearch=Nem található a keresett $1
|
||||
index_toomany2=Túl sok megjelenítendő munka. Használja a keresési mezőt a lista szűrésére!
|
||||
index_search=Időzített feladat (Cron munka) keresése:
|
||||
index_ok=Keresés
|
||||
ui_searchok=Keresés
|
||||
index_searchres=Egyező Cron munkák: $1 ..
|
||||
index_reset=Keresés visszaállítása.
|
||||
index_econfigcheck=A Cron munkákat nem tudjuk kezelni az ön rendszerén, mivel a modul beállítások nem megfelelőek: $1
|
||||
|
||||
@@ -6,7 +6,7 @@ index_ecrondir_create=Prova a creare la directory dei lavori $1 ?
|
||||
index_esearch=Nessun lavoro corrisponde alla tua ricerca per $1.
|
||||
index_toomany2=Ci sono troppi lavori da mostrare. Utilizzare il modulo di ricerca sopra per limitare l'elenco.
|
||||
index_search=Trova i lavori Cron corrispondenti
|
||||
index_ok=Ricerca
|
||||
ui_searchok=Ricerca
|
||||
index_searchres=Cron lavori corrispondenti a $1 ..
|
||||
index_reset=Reimposta ricerca.
|
||||
index_econfigcheck=I lavori Cron non possono essere gestiti sul sistema in quanto la configurazione del modulo non è valida : $1
|
||||
|
||||
@@ -15,7 +15,7 @@ index_enable=選択したジョブを有効にする
|
||||
index_esearch=$1の検索に一致するジョブはありません。
|
||||
index_toomany2=表示するジョブが多すぎます。上記の検索フォームを使用して、リストを制限します。
|
||||
index_search=一致するCronジョブを検索
|
||||
index_ok=探す
|
||||
ui_searchok=探す
|
||||
index_searchres=$1に一致するCronジョブ ..
|
||||
index_reset=検索をリセットします。
|
||||
index_econfigcheck=モジュール構成が無効であるため、cronジョブをシステムで管理できません: $1
|
||||
|
||||
@@ -19,7 +19,7 @@ index_enable=선택된 작업 사용
|
||||
index_esearch=$1 에 대한 검색과 일치하는 작업이 없습니다.
|
||||
index_toomany2=표시 할 작업이 너무 많습니다. 위의 검색 양식을 사용하여 목록을 제한하십시오.
|
||||
index_search=일치하는 Cron 작업 찾기
|
||||
index_ok=검색
|
||||
ui_searchok=검색
|
||||
index_searchres=$1 과 (와) 일치하는 Cron 작업
|
||||
index_reset=검색을 재설정하십시오.
|
||||
index_econfigcheck=모듈 구성이 유효하지 않으므로 시스템에서 Cron 작업을 관리 할 수 없습니다 : $1
|
||||
|
||||
@@ -23,7 +23,7 @@ index_enable=Membolehkan Tugas Terpilih
|
||||
index_esearch=Tiada tugas yang sepadan dengan carian anda untuk $1.
|
||||
index_toomany2=Terdapat terlalu banyak tugas untuk dipaparkan. Guna borang carian di atas untuk menghadkan senarai.
|
||||
index_search=Mencari tugas Cron yang sepadan
|
||||
index_ok=Carian
|
||||
ui_searchok=Carian
|
||||
index_searchres=Tugas Cron yang sepadan $1 ..
|
||||
index_reset=Tetapan semula carian.
|
||||
index_econfigcheck=Tugas Cron tidak boleh diuruskan pada sistem anda, seperti konfigurasi modul itu tidak sah: $1
|
||||
|
||||
@@ -23,7 +23,7 @@ index_enable=Aanzetten Geselecteerde Taken
|
||||
index_esearch=Geen taken komen overeen voor de zoekopdracht naar $1
|
||||
index_toomany2=Er zijn teveel jobs om te laten zien. Gebruik het zoek formulier hierboven om een kleinere lijst te krijgen.
|
||||
index_search=Vind cron jobs die overeenkomen met
|
||||
index_ok=Zoeken
|
||||
ui_searchok=Zoeken
|
||||
index_searchres=Cron taken die overeenkomen met $1..
|
||||
index_reset=Reset Zoeken
|
||||
index_econfigcheck=Cron jobs kunnen niet beheerd worden op uw systeem, omdat de module configuratie niet geldig is : $1
|
||||
|
||||
@@ -27,7 +27,7 @@ index_enable=Slå på valgte jobber
|
||||
index_esearch=Ingen jobber stemte med søket ditt etter $1.
|
||||
index_toomany2=Det er for mange jobber å vise. Bruk søkeskjemaet ovenfor til å begrense listen.
|
||||
index_search=Finn Cron jobber som stemmer med
|
||||
index_ok=Søk
|
||||
ui_searchok=Søk
|
||||
index_searchres=Cron jobber som stemmer med $1 ..
|
||||
index_reset=Tilbakestill søk.
|
||||
index_econfigcheck=Cron jobber kan ikke vedlikeholdes på systemet ditt, da modulkonfigurasjonen ikke er gyldig : $1
|
||||
|
||||
@@ -27,7 +27,7 @@ index_enable=Włącz wybrane zadania
|
||||
index_esearch=Brak zadań pasujących do wyszukiwania $1.
|
||||
index_toomany2=Za dużo zadań do wyświetlenia. Użyj wyszukiwania powyżej, aby ograniczyć listę.
|
||||
index_search=Znajdź zadania Cron pasujące do
|
||||
index_ok=Szukaj
|
||||
ui_searchok=Szukaj
|
||||
index_searchres=Zadania Cron pasujące do $1 ..
|
||||
index_reset=Resetuj wyszukiwanie.
|
||||
index_econfigcheck=Zarządzanie zadaniami Cron nie jest możliwe na Twoim systemie, ponieważ konfiguracja modułu jest nieprawidłowa: $1
|
||||
|
||||
@@ -19,7 +19,7 @@ index_enable=Ativar trabalhos selecionados
|
||||
index_esearch=Nenhum trabalho corresponde à sua pesquisa por $1.
|
||||
index_toomany2=Existem muitos empregos para mostrar. Use o formulário de pesquisa acima para limitar a lista.
|
||||
index_search=Encontrar Cron empregos correspondentes
|
||||
index_ok=Procurar
|
||||
ui_searchok=Procurar
|
||||
index_searchres=Trabalhos Cron correspondentes a $1 ..
|
||||
index_reset=Redefinir pesquisa.
|
||||
index_econfigcheck=Trabalhos Cron não podem ser gerenciados no seu sistema, pois a configuração do módulo não é válida : $1
|
||||
|
||||
@@ -23,7 +23,7 @@ index_enable=Habilitar Tarefas Selecionadas
|
||||
index_esearch=Nenhuma tarefa foi encontrada usando o termo de busca $1.
|
||||
index_toomany2=Há muitas tarefas para exibir. Use os filtros de busca acima para limitar a lista.
|
||||
index_search=Encontrar tarefas Cron com a expressão
|
||||
index_ok=Procurar
|
||||
ui_searchok=Procurar
|
||||
index_searchres=Tarefas Cron com a expressão $1 ..
|
||||
index_reset=Limpar busca.
|
||||
index_econfigcheck=Não é possível gerenciar tarefas Cron no seu sistema, pois a configuração de módulo não é válida: $1
|
||||
|
||||
@@ -27,7 +27,7 @@ index_enable=Включить Выбранные Задания
|
||||
index_esearch=По вашему запросу $1 не найдено ни одного задания.
|
||||
index_toomany2=Слишком много вариантов. Воспользуйтесь поиском выше, чтобы ограничить результат.
|
||||
index_search=Найти подходящие задания Cron
|
||||
index_ok=Поиск
|
||||
ui_searchok=Поиск
|
||||
index_searchres=Задания Cron, соответствующие $1 ..
|
||||
index_reset=Сбросить поиск.
|
||||
index_econfigcheck=Заданиями Cron нельзя управлять в вашей системе, так как конфигурация модуля неверна : $1
|
||||
|
||||
@@ -25,7 +25,7 @@ index_enable=Povoliť vybrané úlohy
|
||||
index_esearch=Vášmu vyhľadávaniu pre $1 nezodpovedali žiadne úlohy.
|
||||
index_toomany2=Je príliš veľa pracovných miest na zobrazenie. Zoznam obmedzíte pomocou vyhľadávacieho formulára vyššie.
|
||||
index_search=Nájdite zodpovedajúce úlohy spoločnosti Cron
|
||||
index_ok=Vyhľadávanie
|
||||
ui_searchok=Vyhľadávanie
|
||||
index_searchres=Cron pracovných miest zodpovedá $1 ..
|
||||
index_reset=Obnoviť vyhľadávanie.
|
||||
index_econfigcheck=Vo vašom systéme nie je možné spravovať úlohy Cron, pretože konfigurácia modulu nie je platná : $1
|
||||
|
||||
@@ -19,7 +19,7 @@ index_enable=Aktivera utvalda jobb
|
||||
index_esearch=Inga jobb matchade din sökning efter $1.
|
||||
index_toomany2=Det finns för många jobb att visa. Använd sökformuläret ovan för att begränsa listan.
|
||||
index_search=Hitta Cron jobb matchning
|
||||
index_ok=Sök
|
||||
ui_searchok=Sök
|
||||
index_searchres=Cron jobb matchar $1 ..
|
||||
index_reset=Återställ sökningen.
|
||||
index_econfigcheck=Cron-jobb kan inte hanteras på ditt system, eftersom modulkonfigurationen inte är giltig : $1
|
||||
|
||||
@@ -13,7 +13,7 @@ index_enable=Seçilen İşleri Etkinleştir
|
||||
index_esearch=$1 için aramanızla eşleşen iş yok.
|
||||
index_toomany2=Gösterilecek çok fazla iş var. Listeyi sınırlamak için yukarıdaki arama formunu kullanın.
|
||||
index_search=Eşleşen Cron işlerini bulun
|
||||
index_ok=Arama
|
||||
ui_searchok=Arama
|
||||
index_searchres=$1 ile eşleşen Cron işleri
|
||||
index_reset=Aramayı sıfırla.
|
||||
index_econfigcheck=Modül yapılandırması geçerli olmadığı için Cron işleri sisteminizde yönetilemiyor : $1
|
||||
|
||||
@@ -19,7 +19,7 @@ index_enable=Увімкнути вибрані завдання
|
||||
index_esearch=Жодна робота не відповідала вашому пошуку для $1.
|
||||
index_toomany2=Занадто багато робочих місць для показу. Використовуйте форму пошуку вище, щоб обмежити список.
|
||||
index_search=Знайдіть відповідність завданням Cron
|
||||
index_ok=Пошук
|
||||
ui_searchok=Пошук
|
||||
index_searchres=Завдання Cron відповідають $1.
|
||||
index_reset=Скинути пошук.
|
||||
index_econfigcheck=Завданнями Cron не можна керувати у вашій системі, оскільки конфігурація модуля недійсна : $1
|
||||
|
||||
@@ -18,7 +18,7 @@ index_enable=启用所选作业
|
||||
index_esearch=没有职位与您对 $1的搜索匹配。
|
||||
index_toomany2=有太多工作要显示。使用上面的搜索表单来限制列表。
|
||||
index_search=查找匹配的Cron职位
|
||||
index_ok=搜索
|
||||
ui_searchok=搜索
|
||||
index_searchres=与 $1..相匹配的Cron作业
|
||||
index_reset=重置搜索。
|
||||
index_econfigcheck=Cron作业无法在您的系统上管理,因为模块配置无效: $1
|
||||
|
||||
@@ -19,7 +19,7 @@ index_enable=啟用所選作業
|
||||
index_esearch=沒有職位與您對 $1的搜索匹配。
|
||||
index_toomany2=有太多工作要顯示。使用上面的搜索表單來限制列表。
|
||||
index_search=查找匹配的Cron職位
|
||||
index_ok=搜索
|
||||
ui_searchok=搜索
|
||||
index_searchres=與 $1..相匹配的Cron作業
|
||||
index_reset=重置搜索。
|
||||
index_econfigcheck=Cron作業無法在您的系統上管理,因為模塊配置無效: $1
|
||||
|
||||
@@ -85,7 +85,11 @@ else {
|
||||
if ($in{"protocol_$i"}) {
|
||||
push(@opts, "protocol=".$in{"protocol_$i"});
|
||||
}
|
||||
push(@opts, split(/\s+/, $in{"others_$i"}));
|
||||
foreach my $oo (split(/\s+/, $in{"others_$i"})) {
|
||||
my ($n, $v) = split(/=/, $oo, 2);
|
||||
$v = "\"$v\"" if ($v =~ /\s|,|=/ && $v !~ /['"]/);
|
||||
push(@opts, "$n=$v");
|
||||
}
|
||||
push(@actions, $in{"action_$i"}."[".join(", ", @opts)."]");
|
||||
}
|
||||
|
||||
|
||||
205
fastrpc.cgi
@@ -10,6 +10,10 @@ use POSIX;
|
||||
use Socket;
|
||||
$force_lang = $default_lang;
|
||||
&init_config();
|
||||
|
||||
my $DEFAULT_RPC_TIMEOUT = 60;
|
||||
my $DEFAULT_RPC_IDLE_FACTOR = 6;
|
||||
|
||||
print "Content-type: text/plain\n\n";
|
||||
|
||||
# Can this user make remote calls?
|
||||
@@ -34,7 +38,7 @@ if ($aerr) {
|
||||
exit;
|
||||
}
|
||||
if (open(RANDOM, "/dev/urandom")) {
|
||||
local $tmpsid;
|
||||
my $tmpsid;
|
||||
read(RANDOM, $tmpsid, 16);
|
||||
$sid = lc(unpack('h*', $tmpsid));
|
||||
close RANDOM;
|
||||
@@ -45,6 +49,16 @@ else {
|
||||
$version = &get_webmin_version();
|
||||
print "1 $port $sid $version\n";
|
||||
|
||||
# Timeout
|
||||
my $rpc_idle_factor = $gconfig{'rpc_idle_factor'} || $DEFAULT_RPC_IDLE_FACTOR;
|
||||
if ($rpc_idle_factor !~ /^\d+$/ || $rpc_idle_factor < 1) {
|
||||
$rpc_idle_factor = $DEFAULT_RPC_IDLE_FACTOR;
|
||||
}
|
||||
my $config_rpc_timeout = $gconfig{'rpc_timeout'} || $DEFAULT_RPC_TIMEOUT;
|
||||
if ($config_rpc_timeout !~ /^\d+$/ || $config_rpc_timeout < 1) {
|
||||
$config_rpc_timeout = $DEFAULT_RPC_TIMEOUT;
|
||||
}
|
||||
|
||||
# Fork and listen for calls ..
|
||||
$pid = fork();
|
||||
if ($pid < 0) {
|
||||
@@ -57,14 +71,14 @@ untie(*STDIN);
|
||||
untie(*STDOUT);
|
||||
|
||||
# Accept the TCP connection
|
||||
local $rmask;
|
||||
my $rmask;
|
||||
vec($rmask, fileno(MAIN), 1) = 1;
|
||||
if ($use_ipv6) {
|
||||
vec($rmask, fileno(MAIN6), 1) = 1;
|
||||
}
|
||||
$sel = select($rmask, undef, undef, 60);
|
||||
$sel = select($rmask, undef, undef, $config_rpc_timeout);
|
||||
if ($sel <= 0) {
|
||||
print STDERR "fastrpc: accept timed out\n"
|
||||
print STDERR "fastrpc[$$]: accept timed out\n"
|
||||
if ($gconfig{'rpcdebug'});
|
||||
exit;
|
||||
}
|
||||
@@ -78,63 +92,83 @@ else {
|
||||
die "No connection on any socket!";
|
||||
}
|
||||
die "accept failed : $!" if (!$acptaddr);
|
||||
$oldsel = select(SOCK);
|
||||
my $oldsel = select(SOCK);
|
||||
$| = 1;
|
||||
select($oldsel);
|
||||
|
||||
$rcount = 0;
|
||||
my $rcount = 0;
|
||||
my %xfer_kids;
|
||||
while(1) {
|
||||
# Clean up the list of waiting sub-processes
|
||||
foreach my $p (keys %xfer_kids) {
|
||||
my $waited_pid = waitpid($p, POSIX::WNOHANG());
|
||||
delete($xfer_kids{$p}) if ($waited_pid > 0 || $waited_pid == -1);
|
||||
}
|
||||
|
||||
# Wait for the request. Wait longer if this isn't the first one
|
||||
local $rmask;
|
||||
my $rmask;
|
||||
vec($rmask, fileno(SOCK), 1) = 1;
|
||||
local $sel = select($rmask, undef, undef, $rcount ? 360 : 60);
|
||||
my $timeout = $rcount
|
||||
? $config_rpc_timeout * $rpc_idle_factor
|
||||
: $config_rpc_timeout;
|
||||
my $sel = select($rmask, undef, undef, $timeout);
|
||||
if ($sel <= 0) {
|
||||
print STDERR "fastrpc: session timed out\n"
|
||||
# Don't kill the control session while a tcpwrite/tcpread is
|
||||
# running
|
||||
my $nk = scalar(keys %xfer_kids);
|
||||
if ($nk) {
|
||||
print STDERR "fastrpc[$$]: idle timeout, but $nk ".
|
||||
"transfer(s) active: ".
|
||||
join(",", sort keys %xfer_kids)."\n"
|
||||
if ($gconfig{'rpcdebug'});
|
||||
next;
|
||||
}
|
||||
print STDERR "fastrpc[$$]: session timed out\n"
|
||||
if ($gconfig{'rpcdebug'});
|
||||
last;
|
||||
}
|
||||
|
||||
local $line = <SOCK>;
|
||||
my $line = <SOCK>;
|
||||
last if (!$line);
|
||||
local ($len, $auth) = split(/\s+/, $line);
|
||||
my ($len, $auth) = split(/\s+/, $line);
|
||||
die "Invalid session ID" if ($auth ne $sid);
|
||||
local $rawarg;
|
||||
my $rawarg;
|
||||
while(length($rawarg) < $len) {
|
||||
local $got;
|
||||
local $rv = read(SOCK, $got, $len - length($rawarg));
|
||||
my $got;
|
||||
my $rv = read(SOCK, $got, $len - length($rawarg));
|
||||
exit if ($rv <= 0);
|
||||
$rawarg .= $got;
|
||||
}
|
||||
print STDERR "fastrpc: raw $rawarg\n" if ($gconfig{'rpcdebug'});
|
||||
local $dumper = substr($rawarg, 0, 5) eq '$VAR1' ? 1 : 0;
|
||||
local $arg = &unserialise_variable($rawarg);
|
||||
print STDERR "fastrpc[$$]: raw $rawarg\n" if ($gconfig{'rpcdebug'});
|
||||
my $dumper = substr($rawarg, 0, 5) eq '$VAR1' ? 1 : 0;
|
||||
my $arg = &unserialise_variable($rawarg);
|
||||
|
||||
# Process it
|
||||
local $rv;
|
||||
my $rv;
|
||||
if ($arg->{'action'} eq 'ping') {
|
||||
# Just respond with an OK
|
||||
print STDERR "fastrpc: ping\n" if ($gconfig{'rpcdebug'});
|
||||
print STDERR "fastrpc[$$]: ping\n" if ($gconfig{'rpcdebug'});
|
||||
$rv = { 'status' => 1 };
|
||||
}
|
||||
elsif ($arg->{'action'} eq 'check') {
|
||||
# Check if some module is supported
|
||||
print STDERR "fastrpc: check $arg->{'module'}\n" if ($gconfig{'rpcdebug'});
|
||||
print STDERR "fastrpc[$$]: check $arg->{'module'}\n" if ($gconfig{'rpcdebug'});
|
||||
$rv = { 'status' => 1,
|
||||
'rv' => &foreign_check($arg->{'module'}, undef, undef,
|
||||
$arg->{'api'}) };
|
||||
}
|
||||
elsif ($arg->{'action'} eq 'config') {
|
||||
# Get the config for some module
|
||||
print STDERR "fastrpc: config $arg->{'module'}\n" if ($gconfig{'rpcdebug'});
|
||||
local %config = &foreign_config($arg->{'module'});
|
||||
print STDERR "fastrpc[$$]: config $arg->{'module'}\n" if ($gconfig{'rpcdebug'});
|
||||
my %config = &foreign_config($arg->{'module'});
|
||||
$rv = { 'status' => 1, 'rv' => \%config };
|
||||
}
|
||||
elsif ($arg->{'action'} eq 'write') {
|
||||
# Transfer data to a local temp file
|
||||
local $file = $arg->{'file'} ? $arg->{'file'} :
|
||||
# Transfer data to a my temp file
|
||||
my $file = $arg->{'file'} ? $arg->{'file'} :
|
||||
$arg->{'name'} ? &tempname($arg->{'name'}) :
|
||||
&tempname();
|
||||
print STDERR "fastrpc: write $file\n" if ($gconfig{'rpcdebug'});
|
||||
print STDERR "fastrpc[$$]: write $file\n" if ($gconfig{'rpcdebug'});
|
||||
open(FILE, ">$file");
|
||||
binmode(FILE);
|
||||
print FILE $arg->{'data'};
|
||||
@@ -142,24 +176,32 @@ while(1) {
|
||||
$rv = { 'status' => 1, 'rv' => $file };
|
||||
}
|
||||
elsif ($arg->{'action'} eq 'tcpwrite') {
|
||||
# Transfer data to a local temp file over TCP connection
|
||||
local $file = $arg->{'file'} ? $arg->{'file'} :
|
||||
# Transfer data to a my temp file over TCP connection
|
||||
my $file = $arg->{'file'} ? $arg->{'file'} :
|
||||
$arg->{'name'} ? &tempname($arg->{'name'}) :
|
||||
&tempname();
|
||||
print STDERR "fastrpc: tcpwrite $file\n" if ($gconfig{'rpcdebug'});
|
||||
local $tsock = time().$$;
|
||||
local $tsock6 = $use_ipv6 ? time().$$."v6" : undef;
|
||||
local $tport = $port + 1;
|
||||
print STDERR "fastrpc[$$]: tcpwrite $file\n" if ($gconfig{'rpcdebug'});
|
||||
my $tsock = time().$$;
|
||||
my $tsock6 = $use_ipv6 ? time().$$."v6" : undef;
|
||||
my $tport = $port + 1;
|
||||
&allocate_socket($tsock, $tsock6, \$tport);
|
||||
if (!fork()) {
|
||||
my $cpid = fork();
|
||||
if (!defined($cpid)) {
|
||||
$rv = { 'status' => 0, 'rv' => "fork() failed : $!" };
|
||||
}
|
||||
elsif ($cpid == 0) {
|
||||
close(SOCK);
|
||||
close(MAIN);
|
||||
close(MAIN6) if ($use_ipv6);
|
||||
# Accept connection in separate process
|
||||
print STDERR "fastrpc: tcpwrite $file port $tport\n" if ($gconfig{'rpcdebug'});
|
||||
local $rmask;
|
||||
print STDERR "fastrpc[$$]: tcpwrite $file port $tport\n"
|
||||
if ($gconfig{'rpcdebug'});
|
||||
my $rmask;
|
||||
vec($rmask, fileno($tsock), 1) = 1;
|
||||
if ($use_ipv6) {
|
||||
vec($rmask, fileno($tsock6), 1) = 1;
|
||||
}
|
||||
local $sel = select($rmask, undef, undef, 30);
|
||||
my $sel = select($rmask, undef, undef, 30);
|
||||
exit if ($sel <= 0);
|
||||
if (vec($rmask, fileno($tsock), 1)) {
|
||||
accept(TRANS, $tsock) || exit;
|
||||
@@ -167,40 +209,44 @@ while(1) {
|
||||
elsif ($use_ipv6 && vec($rmask, fileno($tsock6), 1)) {
|
||||
accept(TRANS, $tsock6) || exit;
|
||||
}
|
||||
print STDERR "fastrpc: tcpwrite $file accepted\n" if ($gconfig{'rpcdebug'});
|
||||
local $buf;
|
||||
local $err;
|
||||
print STDERR "fastrpc[$$]: tcpwrite $file accepted\n" if ($gconfig{'rpcdebug'});
|
||||
my $buf;
|
||||
my $err;
|
||||
if (open(FILE, ">$file")) {
|
||||
binmode(FILE);
|
||||
print STDERR "fastrpc: tcpwrite $file writing\n" if ($gconfig{'rpcdebug'});
|
||||
print STDERR "fastrpc[$$]: tcpwrite $file writing\n" if ($gconfig{'rpcdebug'});
|
||||
my $bs = &get_buffer_size();
|
||||
while(read(TRANS, $buf, $bs) > 0) {
|
||||
local $ok = (print FILE $buf);
|
||||
my $ok = (print FILE $buf);
|
||||
if (!$ok) {
|
||||
$err = "Write to $file failed : $!";
|
||||
last;
|
||||
}
|
||||
}
|
||||
close(FILE);
|
||||
print STDERR "fastrpc: tcpwrite $file written\n" if ($gconfig{'rpcdebug'});
|
||||
print STDERR "fastrpc[$$]: tcpwrite $file written\n" if ($gconfig{'rpcdebug'});
|
||||
}
|
||||
else {
|
||||
print STDERR "fastrpc: tcpwrite $file open failed $!\n" if ($gconfig{'rpcdebug'});
|
||||
print STDERR "fastrpc[$$]: tcpwrite $file open failed $!\n" if ($gconfig{'rpcdebug'});
|
||||
$err = "Failed to open $file : $!";
|
||||
}
|
||||
print TRANS $err ? "$err\n" : "OK\n";
|
||||
close(TRANS);
|
||||
exit;
|
||||
}
|
||||
else {
|
||||
$xfer_kids{$cpid} = 1;
|
||||
print STDERR "fastrpc[$$]: tcpwrite $file started\n"
|
||||
if ($gconfig{'rpcdebug'});
|
||||
$rv = { 'status' => 1, 'rv' => [ $file, $tport ] };
|
||||
}
|
||||
close($tsock);
|
||||
close($tsock6);
|
||||
print STDERR "fastrpc: tcpwrite $file done\n" if ($gconfig{'rpcdebug'});
|
||||
$rv = { 'status' => 1, 'rv' => [ $file, $tport ] };
|
||||
close($tsock6) if ($use_ipv6);
|
||||
}
|
||||
elsif ($arg->{'action'} eq 'read') {
|
||||
# Transfer data from a file
|
||||
print STDERR "fastrpc: read $arg->{'file'}\n" if ($gconfig{'rpcdebug'});
|
||||
local ($data, $got);
|
||||
print STDERR "fastrpc[$$]: read $arg->{'file'}\n" if ($gconfig{'rpcdebug'});
|
||||
my ($data, $got);
|
||||
open(FILE, "<$arg->{'file'}");
|
||||
binmode(FILE);
|
||||
my $bs = &get_buffer_size();
|
||||
@@ -212,7 +258,7 @@ while(1) {
|
||||
}
|
||||
elsif ($arg->{'action'} eq 'tcpread') {
|
||||
# Transfer data from a file over TCP connection
|
||||
print STDERR "fastrpc: tcpread $arg->{'file'}\n" if ($gconfig{'rpcdebug'});
|
||||
print STDERR "fastrpc[$$]: tcpread $arg->{'file'}\n" if ($gconfig{'rpcdebug'});
|
||||
if (-d $arg->{'file'}) {
|
||||
$rv = { 'status' => 1, 'rv' => [ undef, "$arg->{'file'} is a directory" ] };
|
||||
}
|
||||
@@ -221,18 +267,25 @@ while(1) {
|
||||
}
|
||||
else {
|
||||
binmode(FILE);
|
||||
local $tsock = time().$$;
|
||||
local $tsock6 = $use_ipv6 ? time().$$."v6" : undef;
|
||||
local $tport = $port + 1;
|
||||
my $tsock = time().$$;
|
||||
my $tsock6 = $use_ipv6 ? time().$$."v6" : undef;
|
||||
my $tport = $port + 1;
|
||||
&allocate_socket($tsock, $tsock6, \$tport);
|
||||
if (!fork()) {
|
||||
my $cpid = fork();
|
||||
if (!defined($cpid)) {
|
||||
$rv = { 'status' => 0, 'rv' => "fork() failed : $!" };
|
||||
}
|
||||
elsif ($cpid == 0) {
|
||||
close(SOCK);
|
||||
close(MAIN);
|
||||
close(MAIN6) if ($use_ipv6);
|
||||
# Accept connection in separate process
|
||||
local $rmask;
|
||||
my $rmask;
|
||||
vec($rmask, fileno($tsock), 1) = 1;
|
||||
if ($use_ipv6) {
|
||||
vec($rmask, fileno($tsock6), 1) = 1;
|
||||
}
|
||||
local $sel = select($rmask, undef, undef, 30);
|
||||
my $sel = select($rmask, undef, undef, 30);
|
||||
exit if ($sel <= 0);
|
||||
if (vec($rmask, fileno($tsock), 1)) {
|
||||
accept(TRANS, $tsock) || exit;
|
||||
@@ -240,7 +293,7 @@ while(1) {
|
||||
elsif (vec($rmask, fileno($tsock6), 1)) {
|
||||
accept(TRANS, $tsock6) || exit;
|
||||
}
|
||||
local $buf;
|
||||
my $buf;
|
||||
while(read(FILE, $buf, 1024) > 0) {
|
||||
print TRANS $buf;
|
||||
}
|
||||
@@ -248,33 +301,39 @@ while(1) {
|
||||
close(TRANS);
|
||||
exit;
|
||||
}
|
||||
else {
|
||||
$xfer_kids{$cpid} = 1;
|
||||
print STDERR "fastrpc[$$]: tcpread $arg->{'file'} ".
|
||||
"started\n"
|
||||
if ($gconfig{'rpcdebug'});
|
||||
$rv = { 'status' => 1,
|
||||
'rv' => [ $arg->{'file'}, $tport ] };
|
||||
}
|
||||
close(FILE);
|
||||
close($tsock);
|
||||
close($tsock6);
|
||||
print STDERR "fastrpc: tcpread $arg->{'file'} done\n" if ($gconfig{'rpcdebug'});
|
||||
$rv = { 'status' => 1, 'rv' => [ $arg->{'file'}, $tport ] };
|
||||
close($tsock6) if ($use_ipv6);
|
||||
}
|
||||
}
|
||||
elsif ($arg->{'action'} eq 'require') {
|
||||
# require a library
|
||||
print STDERR "fastrpc: require $arg->{'module'}/$arg->{'file'}\n" if ($gconfig{'rpcdebug'});
|
||||
print STDERR "fastrpc[$$]: require $arg->{'module'}/$arg->{'file'}\n" if ($gconfig{'rpcdebug'});
|
||||
eval {
|
||||
&foreign_require($arg->{'module'},
|
||||
$arg->{'file'});
|
||||
};
|
||||
if ($@) {
|
||||
print STDERR "fastrpc: require error $@\n" if ($gconfig{'rpcdebug'});
|
||||
print STDERR "fastrpc[$$]: require error $@\n" if ($gconfig{'rpcdebug'});
|
||||
$rv = { 'status' => 0, 'rv' => $@ };
|
||||
}
|
||||
else {
|
||||
print STDERR "fastrpc: require done\n" if ($gconfig{'rpcdebug'});
|
||||
print STDERR "fastrpc[$$]: require done\n" if ($gconfig{'rpcdebug'});
|
||||
$rv = { 'status' => 1 };
|
||||
}
|
||||
}
|
||||
elsif ($arg->{'action'} eq 'call') {
|
||||
# execute a function
|
||||
print STDERR "fastrpc: call $arg->{'module'}::$arg->{'func'}(",join(",", @{$arg->{'args'}}),")\n" if ($gconfig{'rpcdebug'});
|
||||
local @rv;
|
||||
print STDERR "fastrpc[$$]: call $arg->{'module'}::$arg->{'func'}(",join(",", @{$arg->{'args'}}),")\n" if ($gconfig{'rpcdebug'});
|
||||
my @rv;
|
||||
eval {
|
||||
local $main::error_must_die = 1;
|
||||
@rv = &foreign_call($arg->{'module'},
|
||||
@@ -282,7 +341,7 @@ while(1) {
|
||||
@{$arg->{'args'}});
|
||||
};
|
||||
if ($@) {
|
||||
print STDERR "fastrpc: call error $@\n" if ($gconfig{'rpcdebug'});
|
||||
print STDERR "fastrpc[$$]: call error $@\n" if ($gconfig{'rpcdebug'});
|
||||
$rv = { 'status' => 0, 'rv' => $@ };
|
||||
}
|
||||
elsif (@rv == 1) {
|
||||
@@ -291,14 +350,14 @@ while(1) {
|
||||
else {
|
||||
$rv = { 'status' => 1, 'arv' => \@rv };
|
||||
}
|
||||
print STDERR "fastrpc: call $arg->{'module'}::$arg->{'func'} done = ",join(",", @rv),"\n" if ($gconfig{'rpcdebug'});
|
||||
print STDERR "fastrpc[$$]: call $arg->{'module'}::$arg->{'func'} done = ",join(",", @rv),"\n" if ($gconfig{'rpcdebug'});
|
||||
}
|
||||
elsif ($arg->{'action'} eq 'eval') {
|
||||
# eval some perl code
|
||||
print STDERR "fastrpc: eval $arg->{'module'} $arg->{'code'}\n" if ($gconfig{'rpcdebug'});
|
||||
local $erv;
|
||||
print STDERR "fastrpc[$$]: eval $arg->{'module'} $arg->{'code'}\n" if ($gconfig{'rpcdebug'});
|
||||
my $erv;
|
||||
if ($arg->{'module'}) {
|
||||
local $pkg = $arg->{'module'};
|
||||
my $pkg = $arg->{'module'};
|
||||
$pkg =~ s/[^A-Za-z0-9]/_/g;
|
||||
$erv = eval "package $pkg;\n".
|
||||
$arg->{'code'}."\n";
|
||||
@@ -306,7 +365,7 @@ while(1) {
|
||||
else {
|
||||
$erv = eval $arg->{'code'};
|
||||
}
|
||||
print STDERR "fastrpc: eval $arg->{'module'} $arg->{'code'} done = $rv error = $@\n" if ($gconfig{'rpcdebug'});
|
||||
print STDERR "fastrpc[$$]: eval $arg->{'module'} $arg->{'code'} done = $rv error = $@\n" if ($gconfig{'rpcdebug'});
|
||||
if ($@) {
|
||||
$rv = { 'status' => 0, 'rv' => $@ };
|
||||
}
|
||||
@@ -315,11 +374,11 @@ while(1) {
|
||||
}
|
||||
}
|
||||
elsif ($arg->{'action'} eq 'quit') {
|
||||
print STDERR "fastrpc: quit\n" if ($gconfig{'rpcdebug'});
|
||||
print STDERR "fastrpc[$$]: quit\n" if ($gconfig{'rpcdebug'});
|
||||
$rv = { 'status' => 1 };
|
||||
}
|
||||
else {
|
||||
print STDERR "fastrpc: unknown $arg->{'action'}\n" if ($gconfig{'rpcdebug'});
|
||||
print STDERR "fastrpc[$$]: unknown $arg->{'action'}\n" if ($gconfig{'rpcdebug'});
|
||||
$rv = { 'status' => 0 };
|
||||
}
|
||||
$rawrv = &serialise_variable($rv, $dumper);
|
||||
@@ -334,8 +393,8 @@ while(1) {
|
||||
# allocate_socket(handle, ipv6-handle, &port)
|
||||
sub allocate_socket
|
||||
{
|
||||
local ($fh, $fh6, $port) = @_;
|
||||
local $proto = getprotobyname('tcp');
|
||||
my ($fh, $fh6, $port) = @_;
|
||||
my $proto = getprotobyname('tcp');
|
||||
if (!socket($fh, PF_INET, SOCK_STREAM, $proto)) {
|
||||
return "socket failed : $!";
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ if( $in{ 'action' } eq $text{ 'hdparm_apply' } )
|
||||
local $key;
|
||||
foreach $key ( 'a', 'd', 'r', 'k', 'u', 'm', 'c', 'A', 'K', 'P', 'X', 'W', 'S' )
|
||||
{
|
||||
$command .= "-".$key." ".$in{ $key }." " if( $in{ $key } ne "" );
|
||||
$command .= "-".$key." ".quotemeta($in{$key})." " if ($in{$key} ne "");
|
||||
}
|
||||
$command .= $in{ 'drive' }."\n";
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ if ($action ne '-b' && $action ne '-k') {
|
||||
$types .= " ".join(' ', @extra) ;
|
||||
}
|
||||
}
|
||||
my $args = quotemeta($action)." ".$types." ".quotemeta($recursive);
|
||||
my $args = quotemeta($action)." ".$types." ".$recursive;
|
||||
$args =~ s/\s+/ /g;
|
||||
$args = &trim($args);
|
||||
foreach my $file (@files) {
|
||||
|
||||
@@ -30,10 +30,13 @@ if (!$in{'new'}) {
|
||||
$dstmode = 1;
|
||||
($dstportlow, $dstporthigh) = ($1, $2);
|
||||
}
|
||||
else {
|
||||
elsif ($dstports) {
|
||||
$dstmode = 0;
|
||||
$dstport = $dstports;
|
||||
}
|
||||
else {
|
||||
$dstmode = 2;
|
||||
}
|
||||
}
|
||||
else {
|
||||
&ui_print_header(undef, $text{'forward_create'}, "");
|
||||
|
||||
@@ -280,7 +280,7 @@ return $? ? $out : undef;
|
||||
sub parse_firewalld_forward
|
||||
{
|
||||
my ($str) = @_;
|
||||
my %w = map { split(/=/, $_) } split(/:/, $str);
|
||||
my %w = map { split(/=/, $_, 2) } split(/:/, $str);
|
||||
return ($w{'port'}, $w{'proto'}, $w{'toport'}, $w{'toaddr'});
|
||||
}
|
||||
|
||||
|
||||
@@ -118,12 +118,14 @@ if ($out && $dump->{'email'} && &foreign_check("mailboxes")) {
|
||||
# Send the email
|
||||
if (!$ok || !$config{'error_email'}) {
|
||||
# Only send email upon failure, or it requested always
|
||||
&mailboxes::send_text_mail(&mailboxes::get_from_address(),
|
||||
$dump->{'email'},
|
||||
undef,
|
||||
$subject,
|
||||
$data,
|
||||
$config{'smtp_server'});
|
||||
&mailboxes::send_text_mail(
|
||||
&mailboxes::get_from_address(),
|
||||
$dump->{'email'} eq '*' ? $gconfig{'webmin_email_to'}
|
||||
: $dump->{'email'},
|
||||
undef,
|
||||
$subject,
|
||||
$data,
|
||||
$config{'smtp_server'});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ require './fsdump-lib.pl';
|
||||
&foreign_require("cron", "cron-lib.pl");
|
||||
&ReadParse();
|
||||
|
||||
$wet = $gconfig{'webmin_email_to'};
|
||||
if (!$in{'id'}) {
|
||||
# Adding a new backup of some type
|
||||
$access{'edit'} || &error($text{'dump_ecannot1'});
|
||||
@@ -32,7 +33,7 @@ if (!$in{'id'}) {
|
||||
$dump = { 'dir' => $in{'dir'},
|
||||
'fs' => $fs,
|
||||
'rsh' => &has_command("ssh"),
|
||||
'email' => $gconfig{'webmin_email_to'},
|
||||
'email' => $wet ? '*' : undef,
|
||||
$config{'simple_sched'} ?
|
||||
( 'special' => 'daily' ) :
|
||||
( 'mins' => '0',
|
||||
@@ -144,7 +145,10 @@ print &ui_table_row(&hlink($text{'edit_enabled'}, "enabled"),
|
||||
|
||||
# Email address to send output to
|
||||
print &ui_table_row(&hlink($text{'edit_email'}, "email"),
|
||||
&ui_textbox("email", $dump->{'email'}, 30), 3, \@tds);
|
||||
$wet ? &ui_opt_textbox("email",
|
||||
$dump->{'email'} eq '*' ? undef : $dump->{'email'},
|
||||
40, &text('edit_email_def', "<tt>$wet</tt>"))
|
||||
: &ui_textbox("email", $dump->{'email'}, 40));
|
||||
|
||||
# Subject line for email message
|
||||
print &ui_table_row(&hlink($text{'edit_subject'}, "subject"),
|
||||
|
||||
@@ -128,6 +128,7 @@ edit_savenow=Save and Backup Now
|
||||
edit_createnow=Create and Backup Now
|
||||
edit_return=backup
|
||||
edit_email=Email scheduled output to
|
||||
edit_email_def=Webmin default ($1)
|
||||
edit_subject=Email message subject
|
||||
edit_restore=Restore ..
|
||||
edit_to=$1 to $2
|
||||
|
||||
@@ -72,7 +72,7 @@ else {
|
||||
}
|
||||
$dump->{'dir'} = $in{'dir'};
|
||||
$dump->{'fs'} = $in{'fs'};
|
||||
$dump->{'email'} = $in{'email'};
|
||||
$dump->{'email'} = $in{'email_def'} ? '*' : $in{'email'};
|
||||
$dump->{'subject'} = $in{'subject_def'} ? undef : $in{'subject'};
|
||||
if ($access{'extra'}) {
|
||||
$dump->{'extra'} = $in{'extra'};
|
||||
|
||||
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 5.9 KiB |
@@ -505,6 +505,10 @@ details.inline.fit > summary + span {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
details summary {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
[data-second-print]:has(details) + br:has(+[data-x-br]) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
10
lang/en
@@ -319,6 +319,8 @@ progress_incache=Found $1 in cache ..
|
||||
readparse_cdheader=Missing Content-Disposition header
|
||||
readparse_enc=Expecting form-data encoding, but got normal encoding
|
||||
readparse_max=Data exceeded maximum size of $1 bytes
|
||||
readparse_nofile=Missing filename for upload
|
||||
readparse_cannotdir=Cannot open upload directory $1 : $2
|
||||
|
||||
password_expired=Your password has expired, and a new one must be chosen.
|
||||
password_temp=You must select a new password to replace your temporary login.
|
||||
@@ -473,6 +475,14 @@ time_in_mins=In $1 minutes
|
||||
time_in_sec=In $1 second
|
||||
time_in_secs=In $1 seconds
|
||||
time_now=Just now
|
||||
time_second=second
|
||||
time_seconds=seconds
|
||||
time_minute=minute
|
||||
time_minutes=minutes
|
||||
time_hour=hour
|
||||
time_hours=hours
|
||||
time_day=day
|
||||
time_days=days
|
||||
|
||||
defcert_error=Default $1 bundled SSL certificate is being used. It is highly advised to update default <tt>$2</tt> certificate before proceeding with login.
|
||||
|
||||
|
||||
@@ -344,7 +344,7 @@ foreach $c (@$conf) {
|
||||
}
|
||||
print TEMP map { "$_\n" } &directive_lines($_[0]);
|
||||
close(TEMP);
|
||||
&set_ownership_permissions(undef, undef, 0700, $temp);
|
||||
&set_ownership_permissions(undef, undef, 0644, $temp);
|
||||
local $out = &backquote_logged("$config{'logrotate'} -f $temp 2>&1");
|
||||
return ($?, $out);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ journal_since0=Latest available
|
||||
journal_since1=Real-time follow
|
||||
journal_since2=Current boot
|
||||
journal_since2-1=Last boot
|
||||
journal_since30=30 days ago
|
||||
journal_since3=7 days ago
|
||||
journal_since4=24 hours ago
|
||||
journal_since5=8 hours ago
|
||||
|
||||
@@ -36,6 +36,7 @@ return [
|
||||
{ "--follow" => $text{'journal_since1'} },
|
||||
{ "--boot" => $text{'journal_since2'} },
|
||||
{ "--boot -1" => $text{'journal_since2-1'} },
|
||||
{ "--since '30 days ago'" => $text{'journal_since30'} },
|
||||
{ "--since '7 days ago'" => $text{'journal_since3'} },
|
||||
{ "--since '24 hours ago'" => $text{'journal_since4'} },
|
||||
{ "--since '8 hours ago'" => $text{'journal_since5'} },
|
||||
|
||||
@@ -2594,6 +2594,7 @@ close(MAIL);
|
||||
local @st = stat($file);
|
||||
$mail->{'size'} = $st[7];
|
||||
$mail->{'time'} = $st[9];
|
||||
$mail->{'ctime'} = $st[10];
|
||||
|
||||
# Set read flags based on the name
|
||||
if ($_[0] =~ /:2,([A-Za-z]*)$/) {
|
||||
|
||||
@@ -51,6 +51,7 @@ spam_report=Report spam using,1,sa_learn-<tt>sa-learn --spam</tt>,spamassass
|
||||
line3.5=From address options,11
|
||||
from_addr=<tt>From:</tt> address to use when sending email manually,3,From mailbox username
|
||||
webmin_from=<tt>From:</tt> address to use when Webmin sends email,3,Default (<tt>webmin-noreply@<i>yourhost</i></tt>)
|
||||
webmin_from_name=Real name to use in From: address,3,None
|
||||
from_virtualmin=Get <tt>From:</tt> address from Virtualmin?,1,1-Yes,0-No
|
||||
from_dom=Domain to use in <tt>From:</tt> address,3,System hostname
|
||||
no_orig_ip=Include browser IP in <tt>X-Originating</tt>-IP header?,1,0-Yes,1-No
|
||||
|
||||
@@ -97,13 +97,13 @@ mail_reset=Clear
|
||||
mail_logout=Change POP3 login
|
||||
mail_logout2=Change IMAP login
|
||||
mail_sig=Edit Signature
|
||||
mail_jump=Jump to page :
|
||||
mail_jump=Jump to page
|
||||
mail_of=of
|
||||
mail_replyto=Reply to
|
||||
mail_folder=Folder
|
||||
mail_delall=Delete All
|
||||
mail_deltrash=Empty Trash
|
||||
mail_search2=Search for:
|
||||
mail_search2=Search for
|
||||
mail_search3=Find with score above:
|
||||
mail_advanced=Advanced Search
|
||||
mail_return2=User Email
|
||||
@@ -179,7 +179,7 @@ view_crypt_4=Encrypted portion of message was successfully decrypted.
|
||||
view_recv=<a href='$2'>Fetch key ID $1 from keyserver</a>.
|
||||
view_folder=Return to mailbox
|
||||
view_dheader=Detach attachment to server
|
||||
view_detach=Detach file:
|
||||
view_detach=Detach file
|
||||
view_dall=<All files>
|
||||
view_dir=to server file or directory:
|
||||
view_black=Block Sender
|
||||
|
||||
@@ -90,7 +90,7 @@ mail_reset=Clear
|
||||
mail_logout=Change POP3 login
|
||||
mail_logout2=Change IMAP login
|
||||
mail_sig=Edit Signature
|
||||
mail_jump=Jump to page :
|
||||
mail_jump=Jump to page
|
||||
mail_of=of
|
||||
mail_replyto=Reply to
|
||||
mail_folder=Folder
|
||||
|
||||
@@ -600,16 +600,21 @@ return &ui_link("list_mail.cgi?user=$_[0]&folder=$_[1]->{'index'}",$text{'mail_r
|
||||
# Returns the address to use when sending email from a script
|
||||
sub get_from_address
|
||||
{
|
||||
local $host = &get_from_domain();
|
||||
my $host = &get_from_domain();
|
||||
my $rv;
|
||||
if ($config{'webmin_from'} =~ /\@/) {
|
||||
return $config{'webmin_from'};
|
||||
$rv = $config{'webmin_from'};
|
||||
}
|
||||
elsif (!$config{'webmin_from'}) {
|
||||
return "webmin-noreply\@$host";
|
||||
$rv = "webmin-noreply\@$host";
|
||||
}
|
||||
else {
|
||||
return "$config{'webmin_from'}\@$host";
|
||||
$rv = "$config{'webmin_from'}\@$host";
|
||||
}
|
||||
if ($config{'webmin_from_name'}) {
|
||||
$rv = "\"$config{'webmin_from_name'}\" <$rv>";
|
||||
}
|
||||
return $rv;
|
||||
}
|
||||
|
||||
# get_from_domain()
|
||||
|
||||
@@ -109,7 +109,7 @@ if ($product eq "webmin") {
|
||||
$size = int(`du -sk $tmp_dir`);
|
||||
@deps = ( "perl", "libnet-ssleay-perl", "openssl", "libauthen-pam-perl", "libpam-runtime", "libio-pty-perl", "unzip", "shared-mime-info", "tar", "libdigest-sha-perl", "libdigest-md5-perl", "gzip" );
|
||||
$deps = join(", ", @deps);
|
||||
@recommends = ( "libdatetime-perl", "libdatetime-timezone-perl", "libdatetime-locale-perl", "libtime-piece-perl", "libencode-detect-perl", "libtime-hires-perl", "libsocket6-perl", "html2text", "qrencode", "libdbi-perl", "libdbd-mysql-perl", "libjson-xs-perl", "libsys-syslog-perl" );
|
||||
@recommends = ( "libdatetime-perl", "libdatetime-timezone-perl", "libdatetime-locale-perl", "libtime-piece-perl", "libencode-detect-perl", "libtime-hires-perl", "libsocket6-perl", "html2text", "qrencode", "libdbi-perl", "libdbd-mysql-perl", "libdbd-mariadb-perl", "libjson-xs-perl", "libsys-syslog-perl" );
|
||||
$recommends = join(", ", @recommends);
|
||||
open(CONTROL, ">$control_file");
|
||||
print CONTROL <<EOF;
|
||||
|
||||
@@ -287,4 +287,3 @@ sub usage
|
||||
{
|
||||
die "Usage: $0 [--minimal] [--mod-list type] <version>\n";
|
||||
}
|
||||
|
||||
|
||||
@@ -241,6 +241,7 @@ if ($< == 0) {
|
||||
system("cd $usr_dir && chown -R root:bin .");
|
||||
}
|
||||
system("find $usr_dir -name .git | xargs rm -rf");
|
||||
system("find $usr_dir -name .github | xargs rm -rf");
|
||||
system("find $usr_dir -name RELEASE | xargs rm -rf");
|
||||
system("find $usr_dir -name RELEASE.sh | xargs rm -rf");
|
||||
if (-r "$usr_dir/$mod/EXCLUDE") {
|
||||
|
||||
@@ -263,6 +263,7 @@ my $ucprog = ucfirst($prog);
|
||||
system("/bin/mkdir -p /tmp/makemodulerpm");
|
||||
system("cd $par && /bin/cp -rpL $source_mod /tmp/makemodulerpm/$mod");
|
||||
system("/usr/bin/find /tmp/makemodulerpm -name .git | xargs rm -rf");
|
||||
system("/usr/bin/find /tmp/makemodulerpm -name .github | xargs rm -rf");
|
||||
system("/usr/bin/find /tmp/makemodulerpm -name RELEASE | xargs rm -rf");
|
||||
system("/usr/bin/find /tmp/makemodulerpm -name RELEASE.sh | xargs rm -rf");
|
||||
system("/usr/bin/find /tmp/makemodulerpm -name t | xargs rm -rf");
|
||||
@@ -550,6 +551,9 @@ if [ "$istheme" = "1" -a "\$1" = "0" ]; then
|
||||
fi
|
||||
# Run the pre-uninstall script, if we are not upgrading
|
||||
if [ "$prog" = "webmin" -a "\$1" = "0" -a -r "/usr/libexec/$prog/$mod/uninstall.pl" ]; then
|
||||
# Skip if replaced by a different package (wbm-foo - webmin-foo)
|
||||
owner=\$(rpm -qf --qf '%%{NAME}\\n' "/usr/libexec/$prog/$mod/uninstall.pl" 2>/dev/null || true)
|
||||
[ -n "\$owner" -a "\$owner" != "%{name}" ] && exit 0
|
||||
cd /usr/libexec/$prog
|
||||
WEBMIN_CONFIG=/etc/$prog WEBMIN_VAR=/var/$prog /usr/libexec/$prog/run-uninstalls.pl $mod
|
||||
fi
|
||||
|
||||
@@ -88,7 +88,7 @@ Release: $rel
|
||||
Provides: %{name}-%{version} perl(WebminCore)
|
||||
Requires(pre): /usr/bin/perl
|
||||
Requires: /bin/sh /usr/bin/perl perl(lib) perl(open) perl(Net::SSLeay) perl(Time::Local) perl(Data::Dumper) perl(File::Path) perl(File::Basename) perl(Digest::SHA) perl(Digest::MD5) openssl unzip tar gzip
|
||||
Recommends: perl(DateTime) perl(DateTime::TimeZone) perl(DateTime::Locale) perl(Time::Piece) perl(Encode::Detect) perl(Time::HiRes) perl(Socket6) perl(Sys::Syslog) html2text shared-mime-info perl-File-Basename perl-File-Path perl-JSON-XS qrencode perl(DBI) perl(DBD::mysql)
|
||||
Recommends: perl(DateTime) perl(DateTime::TimeZone) perl(DateTime::Locale) perl(Time::Piece) perl(Encode::Detect) perl(Time::HiRes) perl(Socket6) perl(Sys::Syslog) html2text shared-mime-info lsof perl-File-Basename perl-File-Path perl-JSON-XS qrencode perl(DBI) perl(DBD::mysql) perl(DBD::MariaDB)
|
||||
AutoReq: 0
|
||||
License: BSD-3-Clause
|
||||
Group: System/Tools
|
||||
|
||||
84
miniserv.pl
@@ -227,15 +227,7 @@ if ($rand1 eq $rand2) {
|
||||
|
||||
# Check if we can call sudo
|
||||
if ($config{'sudo'} && &has_command("sudo")) {
|
||||
eval "use IO::Pty";
|
||||
if (!$@) {
|
||||
$use_sudo = 1;
|
||||
}
|
||||
else {
|
||||
push(@startup_msg,
|
||||
"Perl module IO::Pty needed for calling sudo is not ".
|
||||
"installed : $@");
|
||||
}
|
||||
$use_sudo = 1;
|
||||
}
|
||||
|
||||
# init days and months for http_date
|
||||
@@ -6042,7 +6034,7 @@ sub check_sudo_permissions
|
||||
{
|
||||
local ($user, $pass) = @_;
|
||||
|
||||
# First try the pipes
|
||||
# First try the cache stored by the main process
|
||||
if ($PASSINw) {
|
||||
print DEBUG "check_sudo_permissions: querying cache for $user\n";
|
||||
print $PASSINw "readsudo $user\n";
|
||||
@@ -6054,27 +6046,18 @@ if ($PASSINw) {
|
||||
}
|
||||
}
|
||||
|
||||
local $ptyfh = new IO::Pty;
|
||||
print DEBUG "check_sudo_permissions: ptyfh=$ptyfh\n";
|
||||
if (!$ptyfh) {
|
||||
&log_error("Failed to create new PTY with IO::Pty");
|
||||
return 0;
|
||||
}
|
||||
local @uinfo = getpwnam($user);
|
||||
# Setup pipes for communication with the sudo sub-process
|
||||
pipe(SUDOINr, SUDOINw);
|
||||
pipe(SUDOOUTr, SUDOOUTw);
|
||||
print DEBUG "check_sudo_permissions\n";
|
||||
|
||||
my @uinfo = getpwnam($user);
|
||||
if (!@uinfo) {
|
||||
&log_error("Unix user $user does not exist for sudo");
|
||||
return 0;
|
||||
}
|
||||
|
||||
# Execute sudo in a sub-process, via a pty
|
||||
local $ttyfh = $ptyfh->slave();
|
||||
print DEBUG "check_sudo_permissions: ttyfh=$ttyfh\n";
|
||||
local $tty = $ptyfh->ttyname();
|
||||
print DEBUG "check_sudo_permissions: tty=$tty\n";
|
||||
chown($uinfo[2], $uinfo[3], $tty);
|
||||
pipe(SUDOr, SUDOw);
|
||||
print DEBUG "check_sudo_permissions: about to fork..\n";
|
||||
local $pid = fork();
|
||||
my $pid = fork();
|
||||
print DEBUG "check_sudo_permissions: fork=$pid pid=$$\n";
|
||||
if ($pid < 0) {
|
||||
&log_error("fork for sudo failed : $!");
|
||||
@@ -6089,40 +6072,37 @@ if (!$pid) {
|
||||
$ENV{'USER'} = $ENV{'LOGNAME'} = $user;
|
||||
$ENV{'HOME'} = $uinfo[7];
|
||||
|
||||
$ptyfh->make_slave_controlling_terminal();
|
||||
close(STDIN); close(STDOUT); close(STDERR);
|
||||
untie(*STDIN); untie(*STDOUT); untie(*STDERR);
|
||||
close($PASSINw); close($PASSOUTr);
|
||||
close(SUDOw);
|
||||
close(SUDOINw); close(SUDOOUTr);
|
||||
close(SOCK);
|
||||
close(MAIN);
|
||||
open(STDIN, "<&SUDOr");
|
||||
open(STDOUT, ">$tty");
|
||||
open(STDIN, "<&SUDOINr");
|
||||
open(STDOUT, ">&SUDOOUTw");
|
||||
open(STDERR, ">&STDOUT");
|
||||
close($ptyfh);
|
||||
exec("sudo -l -S");
|
||||
print "Exec failed : $!\n";
|
||||
exit 1;
|
||||
}
|
||||
print DEBUG "check_sudo_permissions: pid=$pid\n";
|
||||
close(SUDOr);
|
||||
$ptyfh->close_slave();
|
||||
close(SUDOINr);
|
||||
close(SUDOOUTw);
|
||||
|
||||
# Send password, and get back response
|
||||
local $oldfh = select(SUDOw);
|
||||
my $oldfh = select(SUDOINw);
|
||||
$| = 1;
|
||||
select($oldfh);
|
||||
print DEBUG "check_sudo_permissions: about to send pass\n";
|
||||
local $SIG{'PIPE'} = 'ignore'; # Sometimes sudo doesn't ask for a password
|
||||
print SUDOw $pass,"\n";
|
||||
print SUDOINw $pass,"\n";
|
||||
print DEBUG "check_sudo_permissions: sent pass=$pass\n";
|
||||
close(SUDOw);
|
||||
local $out;
|
||||
while(<$ptyfh>) {
|
||||
close(SUDOINw);
|
||||
my $out;
|
||||
while(<SUDOOUTr>) {
|
||||
print DEBUG "check_sudo_permissions: got $_";
|
||||
$out .= $_;
|
||||
}
|
||||
close($ptyfh);
|
||||
close(SUDOOUTr);
|
||||
kill('KILL', $pid);
|
||||
waitpid($pid, 0);
|
||||
local ($ok) = ($out =~ /\(ALL\)\s+ALL|\(ALL\)\s+NOPASSWD:\s+ALL|\(ALL\s*:\s*ALL\)\s+ALL|\(ALL\s*:\s*ALL\)\s+NOPASSWD:\s+ALL/ ? 1 : 0);
|
||||
@@ -7052,19 +7032,23 @@ my %rv;
|
||||
my $cert;
|
||||
|
||||
# Try PEM first
|
||||
my $bio = Net::SSLeay::BIO_new_file($file, 'r');
|
||||
if ($bio) {
|
||||
$cert = Net::SSLeay::PEM_read_bio_X509($bio);
|
||||
Net::SSLeay::BIO_free($bio);
|
||||
}
|
||||
eval {
|
||||
my $bio = Net::SSLeay::BIO_new_file($file, 'r');
|
||||
if ($bio) {
|
||||
$cert = Net::SSLeay::PEM_read_bio_X509($bio);
|
||||
Net::SSLeay::BIO_free($bio);
|
||||
}
|
||||
};
|
||||
|
||||
# Try DER if PEM failed
|
||||
if (!$cert) {
|
||||
my $bio = Net::SSLeay::BIO_new_file($file, 'rb');
|
||||
if ($bio) {
|
||||
$cert = Net::SSLeay::d2i_X509_bio($bio);
|
||||
Net::SSLeay::BIO_free($bio);
|
||||
}
|
||||
eval {
|
||||
my $bio = Net::SSLeay::BIO_new_file($file, 'rb');
|
||||
if ($bio) {
|
||||
$cert = Net::SSLeay::d2i_X509_bio($bio);
|
||||
Net::SSLeay::BIO_free($bio);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
# Certificate not found
|
||||
|
||||
@@ -3,6 +3,5 @@ require 'mysql-lib.pl';
|
||||
|
||||
sub cpan_recommended
|
||||
{
|
||||
return ( "DBI", "DBD::mysql" );
|
||||
return ( "DBI", $mysql_version =~ /mariadb/i ? "DBD::MariaDB" : "DBD::mysql" );
|
||||
}
|
||||
|
||||
|
||||
@@ -63,6 +63,21 @@ $sql_mode = &find_value("sql_mode", $mems);
|
||||
print &ui_table_row($text{'cnf_sqlm'},
|
||||
&ui_opt_textbox("sqlm", $sql_mode, 60, $text{'default'}), 3);
|
||||
|
||||
# Slow query log options
|
||||
$slow_query_log = &find_value("slow_query_log", $mems);
|
||||
print &ui_table_row($text{'cnf_slow'},
|
||||
&ui_yesno_radio("slow", $slow_query_log));
|
||||
|
||||
$long_query_time = &find_value("long_query_time", $mems);
|
||||
print &ui_table_row($text{'cnf_long'},
|
||||
&ui_opt_textbox("long", $long_query_time, 8,
|
||||
$text{'cnf_long_def'})." ".$text{'cnf_long_secs'});
|
||||
|
||||
$slow_query_log_file = &find_value("slow_query_log_file", $mems);
|
||||
print &ui_table_row($text{'cnf_slow_file'},
|
||||
&ui_opt_textbox("slow_file", $slow_query_log_file, 40,
|
||||
$text{'cnf_slow_file_def'}), 3);
|
||||
|
||||
# Show set variables
|
||||
print &ui_table_hr();
|
||||
|
||||
|
||||
@@ -320,14 +320,26 @@ else {
|
||||
if (foreign_available("cpan")) {
|
||||
eval "use DBI";
|
||||
push(@needs, "DBI") if ($@);
|
||||
$nodbi++ if ($@);
|
||||
eval "use DBD::mysql";
|
||||
push(@needs, "DBD::mysql") if ($@);
|
||||
push(@needs, $driver_info->{prefer}) if (!$driver_info->{avail});
|
||||
if (@needs) {
|
||||
$needs = &urlize(join(" ", @needs));
|
||||
print &ui_alert_box(&text(@needs == 2 ? 'index_nomods' : 'index_nomod', @needs,
|
||||
"../cpan/download.cgi?source=3&cpan=$needs&mode=2&return=/$module_name/&returndesc=".
|
||||
&urlize($text{'index_return'})), 'warn');
|
||||
&urlize($text{'index_return'})), 'warn',
|
||||
undef, undef, "");
|
||||
}
|
||||
}
|
||||
# No CPAN module, just check for the driver
|
||||
else {
|
||||
eval "use DBI";
|
||||
push(@needs, "DBI") if ($@);
|
||||
push(@needs, $driver_info->{prefer}) if (!$driver_info->{avail});
|
||||
if (@needs) {
|
||||
print &ui_alert_box(
|
||||
&text(@needs == 2
|
||||
? 'index_nomods_manual'
|
||||
: 'index_nomod_manual', @needs), 'warn',
|
||||
undef, undef, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -438,7 +438,7 @@ tprivs_privs1=Table permissions
|
||||
tprivs_privs2=Field permissions
|
||||
tprivs_all=All
|
||||
tprivs_anon=Anonymous
|
||||
tprivs_add=Add new permissions in database :
|
||||
tprivs_add=Add new permissions in database
|
||||
tprivs_norows=No таблица permissions defined
|
||||
tprivs_return=таблица permissions
|
||||
tprivs_none=None
|
||||
|
||||
@@ -30,6 +30,8 @@ index_version=$2 version $1
|
||||
index_version2=$3 version $1 on $2
|
||||
index_nomod=The Perl module <tt>$1</tt> is not installed on your system, so Webmin will not be able to reliably access your MySQL database. <a href='$2'>Click here</a> to install it now.
|
||||
index_nomods=The Perl modules <tt>$1</tt> and <tt>$2</tt> are not installed on your system, so Webmin will not be able to reliably access your MySQL database. <a href='$3'>Click here</a> to install them now.
|
||||
index_nomod_manual=The Perl module <tt>$1</tt> is not installed on your system, so Webmin will not be able to reliably access your MySQL database. Install it manually using your package manager.
|
||||
index_nomods_manual=The Perl modules <tt>$1</tt> and <tt>$2</tt> are not installed on your system, so Webmin will not be able to reliably access your MySQL database. Install them manually using your package manager.
|
||||
index_mysqlver=The command <tt>$1</tt> returned :
|
||||
index_eenvpass=The MySQL client program $1 does not accept passwords passed using the <tt>MYSQL_PWD</tt> environment variable. To ensure that Webmin is able to fully communicate with MySQL, this option should be turned off on the <a href='$2'>module configuration</a> page. Alternately, you can remove any password set in the <tt>root</tt> user's <tt>.my.cnf</tt> file.
|
||||
index_ecnf=The MySQL config file $1 was not found on your system. Use the <a href='$2'>module configuration</a> page to set the correct path.
|
||||
@@ -451,7 +453,7 @@ tprivs_privs1=Table permissions
|
||||
tprivs_privs2=Field permissions
|
||||
tprivs_all=All
|
||||
tprivs_anon=Anonymous
|
||||
tprivs_add=Add new permissions in database :
|
||||
tprivs_add=Add new permissions in database
|
||||
tprivs_norows=No table permissions defined
|
||||
tprivs_return=table permissions
|
||||
tprivs_none=None
|
||||
@@ -487,8 +489,8 @@ cprivs_user=User
|
||||
cprivs_privs=Permissions
|
||||
cprivs_all=All
|
||||
cprivs_anon=Anonymous
|
||||
cprivs_add=Add new permissions in database and table :
|
||||
cprivs_add2=Add new permissions :
|
||||
cprivs_add=Add new permissions in database and table
|
||||
cprivs_add2=Add new permissions
|
||||
cprivs_norows=No field permissions defined
|
||||
cprivs_return=field permissions
|
||||
cprivs_none=None
|
||||
@@ -765,6 +767,14 @@ cnf_ilt=InnoDB lock timeout (in seconds)
|
||||
cnf_eilt=InnoDB lock timeout must be an integer
|
||||
cnf_sqlm=SQL mode options
|
||||
cnf_esqlm=SQL mode options must be a comma-separate list of flags
|
||||
cnf_slow=Enable slow query log?
|
||||
cnf_slow_file=Slow query log file
|
||||
cnf_slow_file_def=Default path
|
||||
cnf_eslow_file=Missing slow query log file path
|
||||
cnf_long=Time for query to be considered slow
|
||||
cnf_long_def=Default (10 seconds)
|
||||
cnf_long_secs=seconds
|
||||
cnf_elong=Slow query time must be a number of seconds
|
||||
|
||||
manual_title=Edit Config Files
|
||||
manual_file=Edit config file:
|
||||
@@ -875,7 +885,7 @@ root_epass1=No new password entered
|
||||
root_epass2=Passwords do not match
|
||||
root_none=No password!
|
||||
root_auto=Automatic (typically <tt>root</tt>)
|
||||
root_socket=The MySQL <tt>$1</tt> user is using Unix socket authentication, so no password is needed and the password cannot be changed.
|
||||
root_socket=The MySQL <tt>$1</tt> user uses Unix socket authentication, so no password is needed. However, you can switch to password authentication on the <a href='list_users.cgi'>User Permissions</a> page.
|
||||
|
||||
mysqlpass_err=MySQL safe mode
|
||||
mysqlpass_esafecmd=The command $1 needed to start MySQL with authentication disabled was not found
|
||||
|
||||
@@ -10,7 +10,13 @@ $access{'perms'} == 1 || &error($text{'vars_ecannot'});
|
||||
print &ui_alert_box(&text('vars_desc', 'edit_cnf.cgi'), 'warn');
|
||||
|
||||
# Work out which ones can be edited
|
||||
%canedit = map { $_->[0], 1 } &list_system_variables();
|
||||
my %canedit;
|
||||
foreach my $v (&list_system_variables()) {
|
||||
my $vn = $v->[0];
|
||||
$canedit{$vn} = 1;
|
||||
$vn =~ s/-/_/g;
|
||||
$canedit{$vn} = 1;
|
||||
}
|
||||
|
||||
# Show search form
|
||||
print &ui_form_start("list_vars.cgi", undef, undef, "style='float: right;'");
|
||||
@@ -22,12 +28,6 @@ print &ui_form_end();
|
||||
$d = &execute_sql($master_db, "show variables".
|
||||
($in{'search'} ? " like '%".quotemeta($in{'search'})."%'" : ""));
|
||||
if (@{$d->{'data'}}) {
|
||||
print &ui_form_start("save_vars.cgi");
|
||||
print &ui_hidden("search", $in{'search'});
|
||||
@tds = ( "width=5" );
|
||||
print &ui_columns_start([ "",
|
||||
$text{'vars_name'},
|
||||
$text{'vars_value'} ], 100, 0, \@tds);
|
||||
@{$d->{'data'}} = sort {
|
||||
# Editing now (highest priority)
|
||||
($d{$b->[0]} <=> $d{$a->[0]}) ||
|
||||
@@ -35,7 +35,14 @@ if (@{$d->{'data'}}) {
|
||||
($canedit{$b->[0]} <=> $canedit{$a->[0]}) ||
|
||||
# Natural sort for equal priority
|
||||
$a->[0] cmp $b->[0]
|
||||
} @{$d->{'data'}};
|
||||
} @{$d->{'data'}};
|
||||
|
||||
print &ui_form_start("save_vars.cgi");
|
||||
print &ui_hidden("search", $in{'search'});
|
||||
@tds = ( "width=5" );
|
||||
print &ui_columns_start([ "",
|
||||
$text{'vars_name'},
|
||||
$text{'vars_value'} ], 100, 0, \@tds);
|
||||
foreach $v (@{$d->{'data'}}) {
|
||||
if (!$canedit{$v->[0]}) {
|
||||
# Cannot edit, so just show value
|
||||
|
||||
@@ -67,13 +67,44 @@ $password_func = $config{'passwd_mode'} ? "old_password" : "password";
|
||||
'enum', 'set');
|
||||
|
||||
@priv_cols = ('Host', 'User', 'Password', 'Select_priv', 'Insert_priv', 'Update_priv', 'Delete_priv', 'Create_priv', 'Drop_priv', 'Reload_priv', 'Shutdown_priv', 'Process_priv', 'File_priv', 'Grant_priv', 'References_priv', 'Index_priv', 'Alter_priv', 'Show_db_priv', 'Super_priv', 'Create_tmp_table_priv', 'Lock_tables_priv', 'Execute_priv', 'Repl_slave_priv', 'Repl_client_priv', 'Create_view_priv', 'Show_view_priv', 'Create_routine_priv', 'Alter_routine_priv', 'Create_user_priv');
|
||||
|
||||
$driver_info = &dbi_driver_info();
|
||||
if (!$config{'nodbi'}) {
|
||||
# Check if we have DBI::mysql
|
||||
eval <<EOF;
|
||||
use DBI;
|
||||
\$driver_handle = DBI->install_driver("mysql");
|
||||
EOF
|
||||
# Check if we have DBI::mysql or DBI::MariaDB
|
||||
eval "require DBI;
|
||||
\$driver_handle = DBI->install_driver(\$driver_info->{'drv'});";
|
||||
}
|
||||
|
||||
# dbi_driver_info()
|
||||
# Based on the current database variant, returns info about the DBI driver.
|
||||
# Falls back to MySQL if the preferred driver is not available.
|
||||
sub dbi_driver_info
|
||||
{
|
||||
my %dbmap = (
|
||||
'mysql' => { drv => 'mysql', opt => 'mysql', mod => 'DBD::mysql' },
|
||||
'mariadb' => { drv => 'MariaDB', opt => 'mariadb', mod => 'DBD::MariaDB' }
|
||||
);
|
||||
my $want = ($mysql_version && $mysql_version =~ /mariadb/i)
|
||||
? 'mariadb'
|
||||
: 'mysql';
|
||||
|
||||
# Try preferred driver
|
||||
my $m = $dbmap{$want}->{'mod'};
|
||||
my $ok = eval "require $m; 1;";
|
||||
$dbmap{$want}->{'avail'} = $ok ? 1 : 0;
|
||||
$dbmap{$want}->{'prefer'} = $dbmap{$want}->{'mod'};
|
||||
return $dbmap{$want} if $ok;
|
||||
|
||||
# If MariaDB preferred but unavailable, fallback to MySQL
|
||||
if ($want eq 'mariadb') {
|
||||
$m = $dbmap{'mysql'}->{'mod'};
|
||||
$ok = eval "require $m; 1;";
|
||||
$dbmap{'mysql'}->{'avail'} = $ok ? 1 : 0;
|
||||
$dbmap{'mysql'}->{'prefer'} = $dbmap{$want}->{'mod'};
|
||||
return $dbmap{'mysql'};
|
||||
}
|
||||
|
||||
# Preferred driver unavailable, no fallback
|
||||
return $dbmap{$want};
|
||||
}
|
||||
|
||||
# Fix text if we're running MariaDB
|
||||
@@ -324,15 +355,16 @@ $sql = &escape_backslashes_in_quotes($sql);
|
||||
if ($driver_handle && !$config{'nodbi'}) {
|
||||
# Use the DBI interface
|
||||
local $cstr = "database=$_[0]";
|
||||
local $drv = $driver_info->{opt};
|
||||
$cstr .= ";host=$config{'host'}" if ($config{'host'});
|
||||
$cstr .= ";port=$config{'port'}" if ($config{'port'});
|
||||
$cstr .= ";mysql_socket=$config{'sock'}" if ($config{'sock'});
|
||||
$cstr .= ";mysql_read_default_file=$config{'my_cnf'}"
|
||||
$cstr .= ";${drv}_socket=$config{'sock'}" if ($config{'sock'});
|
||||
$cstr .= ";${drv}_read_default_file=$config{'my_cnf'}"
|
||||
if (-r $config{'my_cnf'});
|
||||
if ($config{'ssl'}) {
|
||||
$cstr .= ";mysql_ssl=1";
|
||||
$cstr .= ";${drv}_ssl=1";
|
||||
if ($DBD::mysql::VERSION >= 4.043) {
|
||||
$cstr .= ";mysql_ssl_optional=1";
|
||||
$cstr .= ";${drv}_ssl_optional=1";
|
||||
}
|
||||
}
|
||||
local $dbh = $driver_handle->connect($cstr, $mysql_login, $mysql_pass,
|
||||
@@ -2216,7 +2248,7 @@ return $rv->{'data'}->[0]->[0] =~ /unix_socket/i ? 'socket' : 'password';
|
||||
sub list_authentication_plugins
|
||||
{
|
||||
my ($ver, $variant) = &get_remote_mysql_variant();
|
||||
if ($variant eq "mariadb" && &compare_version_numbers($ver, "10.4") >= 0 ||
|
||||
if ($variant eq "mariadb" && &compare_version_numbers($ver, "10.3") >= 0 ||
|
||||
$variant eq "mysql" && &compare_version_numbers($ver, "5.7.6") >= 0) {
|
||||
my $rv = &execute_sql($master_db, "show plugins");
|
||||
my @plugins = map { $_->[0] } grep { $_->[1] eq 'ACTIVE' &&
|
||||
|
||||
@@ -78,6 +78,18 @@ else {
|
||||
&save_directive($conf, $mysqld, "big-tables",
|
||||
$in{'big-tables'} ? [ "" ] : [ ]);
|
||||
|
||||
# Save slow query log options
|
||||
&save_directive($conf, $mysqld, "slow_query_log",
|
||||
[ $in{'slow'} ]);
|
||||
$in{'slow_file_def'} || $in{'slow_file'} =~ /^\S+$/ ||
|
||||
&error($text{'cnf_eslow_file'});
|
||||
&save_directive($conf, $mysqld, "slow_query_log_file",
|
||||
$in{'slow_file_def'} ? [ ] : [ $in{'slow_file'} ]);
|
||||
$in{'long_def'} || $in{'long'} =~ /^\d+$/ ||
|
||||
&error($text{'cnf_elong'});
|
||||
&save_directive($conf, $mysqld, "long_query_time",
|
||||
$in{'long_def'} ? [ ] : [ $in{'long'} ]);
|
||||
|
||||
# Save set variables
|
||||
%vars = &parse_set_variables(&find_value("set-variable", $mems));
|
||||
foreach $w (@mysql_set_variables) {
|
||||
|
||||
@@ -128,6 +128,7 @@ Ubuntu Linux $1 debian-linux 11.0 $os_release =~ /Ubuntu\s+(20\.[0-9\.]+)/ ||
|
||||
Ubuntu Linux $1 debian-linux 12.0 $os_release =~ /Ubuntu\s+(21\.[0-9\.]+)/ || $etc_issue =~ /Ubuntu.*\s(21\.[0-9\.]+)\s/i || $etc_issue =~ /Ubuntu\s+(hirsute|impish)/i
|
||||
Ubuntu Linux $1 debian-linux 13.0 $os_release =~ /Ubuntu\s+(22\.[0-9\.]+)/ || $etc_issue =~ /Ubuntu.*\s(22\.[0-9\.]+)\s/i || $etc_issue =~ /Ubuntu\s+jammy/i
|
||||
Ubuntu Linux $1 debian-linux 14.0 $os_release =~ /Ubuntu\s+(24\.[0-9\.]+)/ || $etc_issue =~ /Ubuntu.*\s(24\.[0-9\.]+)\s/i || $etc_issue =~ /Ubuntu\s+noble/i
|
||||
Ubuntu Linux $1 debian-linux 15.0 $os_release =~ /Ubuntu\s+(26\.[0-9\.]+)/ || $etc_issue =~ /Ubuntu.*\s(26\.[0-9\.]+)\s/i || $etc_issue =~ /Ubuntu\s+resolute/i
|
||||
Ubuntu Linux $1 debian-linux 3.1 $etc_issue =~ /Ubuntu.*\s([0-9\.]+)\s/i
|
||||
Mepis Linux $1 debian-linux $1 $etc_issue =~ /MEPIS/ && `cat /etc/debian_version 2>/dev/null` =~ /([0-9\.]+)/
|
||||
Mepis Linux $1 debian-linux 4.0 $etc_issue =~ /MEPIS/ && `cat /etc/debian_version 2>/dev/null` =~ /(stable)/
|
||||
|
||||