├── checksum.md5
├── readme.txt
├── checksum.sha512
├── LICENSE.md
├── history.txt
└── acctinfo
/checksum.md5:
--------------------------------------------------------------------------------
1 | c1ed74034aca966230cbe76321cb142b acctinfo
2 |
--------------------------------------------------------------------------------
/readme.txt:
--------------------------------------------------------------------------------
1 |
2 | This script has been moved to https://github.com/CpanelInc/tech-acctinfo
3 |
4 |
5 |
--------------------------------------------------------------------------------
/checksum.sha512:
--------------------------------------------------------------------------------
1 | 59d2353f8ebfd1f594855a4df4259f955f628bec67700e572dcebf6ebaa10d69787ff3b5872ace904336b90381fb6217f21ef08b40fe65a9c559ce9567ac437f acctinfo
2 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | This software is Copyright © 2014-2015 by cPanel, Inc.
2 |
3 | THE SOFTWARE LICENSED HEREUNDER IS PROVIDED "AS IS" AND CPANEL HEREBY DISCLAIMS
4 | ALL WARRANTIES OF ANY KIND, WHETHER EXPRESS OR IMPLIED, RELATING TO THE SOFTWARE,
5 | ITS THIRD PARTY COMPONENTS, AND ANY DATA ACCESSED THEREFROM, OR THE ACCURACY,
6 | TIMELINESS, COMPLETENESS, OR ADEQUACY OF THE SOFTWARE, ITS THIRD PARTY COMPONENTS,
7 | AND ANY DATA ACCESSED THEREFROM, INCLUDING THE IMPLIED WARRANTIES OF TITLE,
8 | MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A PARTICULAR PURPOSE, AND
9 | NON-INFRINGEMENT. CPANEL DOES NOT WARRANT THAT THE SOFTWARE OR ITS THIRD PARTY
10 | COMPONENTS ARE ERROR-FREE OR WILL OPERATE WITHOUT INTERRUPTION. IF THE SOFTWARE,
11 | ITS THIRD PARTY COMPONENTS, OR ANY DATA ACCESSED THEREFROM IS DEFECTIVE, YOU ASSUME
12 | THE SOLE RESPONSIBILITY FOR THE ENTIRE COST OF ALL REPAIR OR INJURY OF ANY KIND, EVEN
13 | IF CPANEL HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DEFECTS OR DAMAGES. NO ORAL OR
14 | WRITTEN INFORMATION OR ADVICE GIVEN BY CPANEL, ITS AFFILIATES, LICENSEES, DEALERS,
15 | SUB-LICENSORS, AGENTS OR EMPLOYEES SHALL CREATE A WARRANTY OR IN ANY WAY.
16 |
17 |
--------------------------------------------------------------------------------
/history.txt:
--------------------------------------------------------------------------------
1 |
2 | #############################################################
3 | #### MOVED TO https://github.com/CpanelInc/tech-acctinfo ####
4 | #############################################################
5 |
6 | V2.4.82- Fix cruft check. Was not finding domains in /etc/named.conf and httpd.conf files
7 | - Thanks Rex
8 | V2.4.82- Add check for reserved usernames
9 | V2.4.82- Add default reseller privileges (now marked with [DEFAULT])
10 |
11 | V2.4.81- Fix logic bug in skipEA4 check - caused php information to not display if no CageFS.
12 |
13 | V2.4.80- Fix bug in --scan. Scanned wrong directory path.
14 |
15 | V2.4.79- Fix regexp bug in --listaddons, --listsubs --listaliased that might cause account bleed.
16 | (reported by H. Borresen)
17 |
18 | V2.4.78- Fix big bug in new listssl section if SSL's are missing.
19 |
20 | V2.4.77- Update --listssl to accommodate new location for SSL's in 68.
21 | V2.4.77- Add /etc/mailips and /etc/mailhelo to --mail section
22 | V2.4.77- Add /etc/ssldomains to --cruft check
23 | V2.4.77- Add pending SSL's for purchased orders (not just AutoSSL)
24 | V2.4.77- Updated readme.txt file
25 |
26 | V2.4.76- Fix check for /etc/vdomainaliases
27 | V2.4.76- Fix cruft check for /etc/named.conf file.
28 | V2.4.76- Add /etc/email_send_limits and /etc/ssldomains to cruft check
29 |
30 | V2.4.75- Add check for integration links Note if they are found.
31 | V2.4.75- Check to see if /etc/vdomainaliases/domain.tld exists when running --mail check.
32 |
33 | V2.4.74- Add CAA record check to --listssl
34 | V2.4.74- Add DMARC record check to --mail
35 | V2.4.74- Add check for missing password hash in /etc/shadow
36 | V2.4.74- Fix grep for cruft check and parked/addon/sub domains which might return invalid data.
37 | V2.4.74- Fix UID_MIN/GID_MIN setting to use values from /etc/login.defs (they were hard coded)
38 |
39 | V2.4.73- Add a --nocode option to skip displaying and code blocks for ticket notes.
40 |
41 | V2.4.72- Add code tags to output (for easier ticket pasting)
42 | V2.4.72- Add SANs to certificates
43 | V2.4.72- Add check on feature list to make sure AutoSSL is enabled at feature list.
44 | V2.4.72- Add AutoSSL provider check.
45 |
46 | V2.4.71- Fix grep that was taking too long to complete searching for suPHP_ConfigPath in .htaccess
47 | V2.4.71- Fix HOMEMATCH search in cruft check if HOMEMATCH is not defined it should skip.
48 |
49 | V2.4.70- A couple of small bug fixes that were really bugging me!
50 |
51 | V2.4.69- Fix Mail Routing check (again)
52 | V2.4.69- Add check for multiple homrdirs in cruft check - Thanks Ausaf!
53 |
54 | V2.4.68- Fix grep for Mail Routing (added word boundary)
55 | V2.4.68- Fix loaded configuration file (php.ini) if suPHP_ConfigPath is defined
56 | V2.4.68- Add Disk Quota and Bandwidth Used
57 | V2.4.68- Add DocumentRoot to main domain.
58 | V2.4.68- Code cleanup (colors)
59 |
60 | V2.4.67- Add bandwidth used calculation via uapi if account is over bandwidth limit.
61 | V2.4.67- Change pending autossl check to use username instead of domain name.
62 |
63 | V2.4.66- Fix --scan option to check for existence of username before moving forward, otherwise
64 | it was scanning all of /home
65 | V2.4.66- Add DocumentRoot to addon/sub/aliased domains
66 | V2.4.66- Add pending AutoSSL orders to --listssl
67 |
68 | V2.4.65- Fix CPVersion check (again)
69 | V2.4.65- Remove redundant /etc/localdomains and /etc/remotedomains checks if listed in both files.
70 |
71 | V2.4.64- Add check for theme being x3 and warn if found - can cause UI to not load.
72 | V2.4.64- Use a curl command to grab CloudFlare IP's. No longer maintained in array
73 | V2.4.64- Add more info to reverse DNS updates. Show what it's reversing to (MX, HOSTNAME).
74 |
75 | V2.4.63- Add PHP info for CloudLinux - list which has precedence.
76 | V2.4.62- Add more data to output (max ftp/sql/maillist/pop/addon/sub/parked/backups/autossl)
77 | V2.4.61- Bug Fix - Email addresses containing a period would not display.
78 | V2.4.60- Add reseller shared IP and IP Delegation info (if applicable).
79 | V2.4.59- Fix doveadm quota get command (output stopped working)
80 | V2.4.58- Add -maxdepth 1 to php.ini/.user.ini find command
81 | V2.4.57- Add --skipfind switch to skip searching for user level php.ini/.user.ini files.
82 | V2.4.56- Add additional php information if EA4 PHP version is set to inherit
83 | V2.4.55- Add more information to --mail output (suspended outgoing/hold outgoing etc...)
84 | V2.4.54- Fix CloudLinux PHP Version to not display if CageFS is Disabled,
85 | Made over quota check more informative.
86 | V2.4.53- Add check for custom php.ini, .user.ini files in users home directory. Also add check
87 | for presence of suPHP_ConfigPath in .htaccess files.
88 | V2.4.52- Fix PHP Version check for addon domains
89 | Add php.ini config file information for EA4
90 | Add timestamp to scan with Elapsed time
91 |
92 | v2.4.51- Add spinner to --scan option, exclude mail directory (may add an option to scan that
93 | in the future), clean up scanning code and add colors.
94 |
95 | V2.4.50- Skip any SSL certs not installed. Add a check for expired SSL's and warn if expired
96 |
97 | V2.4.49- Added --useDig switch to skip the Net::DNS setting. Without --useDig, it uses Net::DNS
98 | (see version 2.4.47 below)
99 |
100 | V2.4.49- Rework the Quota check - made it a little faster and CloudLinux fault tolerent.
101 |
102 | V2.4.48- Add simple scan (--scan) to scan for known infection strings.
103 | Add check for demo mode and if bandwidth limit may have been exceeded
104 |
105 | V2.4.47- Revert use of Net::DNS on obtaining A record. Seems to be getting the incorrect
106 | information from time to time. Not sure yet why.
107 |
108 | V2.4.46- Add --noquota check which sometimes causes the quota check to fail on cagefs systems.
109 |
110 | V2.4.45- Add email suspended / email receiving suspended checks
111 |
112 | V2.4.44- Add check for various SPF policy flags, fix email quota rounding
113 |
114 | V2.4.43- Add Net::DNS and Socket code to streamline the A record and MX record check.
115 |
116 | V2.4.40- Add SSL issuer (or warn if self-signed) to ssl check.
117 | Improve quota check for mail.
118 | Add check for MX reverse if it doesn't reverse back to MX record - give warning.
119 | Improve SSL check to display if an SSL Certificate is NOT installed.
120 |
121 | V2.4.40- Add SSL issuer (or warn if self-signed) to ssl check. Improve quota check for mail.
122 | Add check for MX reverse if it doesn't reverse back to MX record - give warning.
123 |
124 | V2.4.39- Add quota info as well as max defer, max emails and mailbox format info to --mail
125 | output. change listresellers switch to reselleraccts. Add --resellerperms switch
126 |
127 | V2.4.38- Fixed bug in EA4 php version check. It was returning an empty string ""
128 |
129 | V2.4.37- Fixed some minor bug fixes and ran through perltidy.
130 |
131 | V2.4.36- Add SPF/DKIM to --mail check, add CloudLinux PHP version if available.
132 |
133 | V2.4.35- Rework/clean the cruft check and add MySQL databases to cruft check.
134 |
135 | V2.4.34- Fix SSL function (was stippring out the TLD for some odd reason).
136 |
137 | V2.4.33- Fix logic error with --mail function (oops)
138 |
139 | V2.4.32- Reworked phpversion (default and account for EA4)
140 | V2.4.32- Reworked SSL certificate check (much smaller now)
141 | V2.4.32- Code clean up
142 |
143 | V2.4.31- Add /etc/valiases and /etc/vfilters to cruft check (Thanks Kyle).
144 |
145 | V2.4.29- Redirect quota STDERR output to /dev/null
146 |
147 | V2.4.28- Fix --mail option to ignore uid:gid in ~/etc/domain.tld/passwd file.
148 |
149 | V2.4.27- Add --mail option. Displays email accounts, aliases, filters, mx records, and
150 | does syntax checking of email routing (/etc/{local,remote}domains), passwd and
151 | shadow files. Still going to add SPF/DKIM info.
152 |
153 | V2.4.26- Fix php version check for EA4 (patch provided by salt-lick) - Thanks!
154 |
155 | V2.4.25- Revamped quota check. Didn't like the first method I had.
156 |
157 | V2.4.24- Fix php version check for EA4 (was changed at some time).
158 |
159 | V2.4.23- Fix quota check if Cannot stat() mounted device error.
160 |
161 | V2.4.22- Added check for custom style (PaperLantern theme)
162 |
163 | V2.4.21- Added quota check and warn if account is over quota.
164 |
165 | V2.4.20- Added permissions check of /home/USERNAME directory to make sure it is 711.
166 |
167 | v2.4.19- Added to cruft check a count of DNS lines in /var/cpanel/users/username file.
168 |
169 | V2.4.17- Fixed SSL info display and added check for uid/gid less than 500 on CentOS 5/6.
170 |
171 | V2.4.16- Added PHP Version check (if EA4)
172 |
173 | V2.4.15- Added CageFS check (if CageFS is installed).
174 |
175 | V2.4.14- Reworked the SSL certificate check (now uses /home/user/ssl/certs)
176 | V2.4.14- Fixed last login IP to only pull the last IP address
177 |
178 | V2.4.11- Added CentOS/CloudLinux Version 7 check - for MINUID less than 1000
179 | Added check for /var/cpanel/databases/username.yaml/json (11.50 uses .json)
180 |
181 | V2.4.10- Fixed empty string in cruft check that was sometimes causing missing data to show as
182 | exists.
183 |
184 | V2.4.9- Removed exit from cruft check if no data found in /var/cpanel/accounting.log
185 | which would allow the cruft check to continue.
186 |
187 | V2.4.8- Completed cruft check (Yay!) - and did a few more bug fixes.
188 |
189 | V2.4.7- Fixed small bug when domain name can not resolve (it was displaying the dig
190 | output with connection timed out)
191 |
192 | V2.4.6- Continued on cruft check - still need to check postgresql databases
193 |
194 | V2.4.2- Started cruft check routine - almost done.
195 | V2.4.2- Added border to end of main output.
196 | V2.4.2- Fixed Usage: display ($0 was sometimes returning /dev/fd/63 instead of acctinfo)
197 | V2.4.2- Added theme and shell information to output.
198 |
199 | V2.4 - Fixed issue with it occasionally getting the wrong real home directory from /etc/passwd
200 | Fixed issue with [Not on this server] IP resolution so that it does not display
201 | default webpage cgi
202 |
203 | V2.3 - Fixed resolved IP check to include NAT check, CloudFlare DNS check, and whether IP address
204 | is on the server or not.
205 |
206 | V2.0 - Almost a complete re-write.
207 |
208 | V1.10 - MODIFIED 10/12/2014 - Added color
209 |
210 | V1.9 - MODIFIED: 10/11/2014 - Cleaned up output.
211 |
212 | V1.8 - BUGFIX: 9/23/2014 - Fixed SSL Certificate display (some SSL certs were not being found).
213 | V1.8 - BUGFIX: 9/23/2014 - Fixed STARTDATE (was not being displayed)
214 | V1.8 - BUGFIX: 9/23/2014 - Fixed display of sub/addon/parked domains (if only 1 of either
215 | was created, it would not show them).
216 |
217 | V1.7 - BUGFIX: 8/22/2014 - PostGreSQL can be installed and not running - psql call would fail.
218 | V1.7 - MODIFIED: 8/22/2014 - Added PostGreSQL table size to output
219 | V1.7 - MODIFIED: 8/22/2014 - Added [Resolves to SAME] if domain resolves to same server IP.
220 |
221 | V1.6 - BUGFIX: 7/27/2014 - if PostGreSQL is not installed the psql command would fail
222 |
223 | v1.5 - MODIFIED: 7/14/2014 - Added postgresql databases and tables.
224 |
225 | v1.4 - MODIFIED: 7/14/2014 - Added "use strict" and set all variables and arrays accordingly.
226 |
227 | v1.3 - MODIFIED: 6/01/2014 - Added --help switch to list the options. (Idea by Citizen Kepler)
228 | v1.3 - MODIFIED: 6/01/2014 - Added a count of all accounts in /etc/trueuserdomains.
229 |
230 | v1.2 - MODIFIED: 5/18/2014 - Added additional switches --listsubs, --listaddons,
231 | --listparked, --listreseller
232 |
233 | v1.1 - MODIFIED: 5/7/2014 - Added --listdbs & --listssls options to list any MySQL DB's
234 | and SSL's (Idea by Tristan Wallace)
235 | v1.1 - MODIFIED: 5/8/2014 - Added -q switch to clear the screen (default is to not clear
236 | the screen) (Idea by Ryan Robson)
237 |
238 | v1.0 - CREATED: 03/28/2014
239 |
--------------------------------------------------------------------------------
/acctinfo:
--------------------------------------------------------------------------------
1 | #!/usr/local/cpanel/3rdparty/bin/perl
2 | # SCRIPT: acctinfo #
3 | # PURPOSE: Get as much information for a username or domain entered at command line #
4 | # as possible. #
5 | # AUTHOR: Peter Elsner #
6 | #######################################################################################
7 |
8 | print < \$listdbs,
89 | 'listssls' => \$listssls,
90 | 'listsubs' => \$listsubs,
91 | 'listaddons' => \$listaddons,
92 | 'listaliased' => \$listaliased,
93 | 'listparked' => \$listaliased,
94 | 'reselleraccts' => \$reselleraccts,
95 | 'resellerperms' => \$resellerperms,
96 | 'resellerprivs' => \$resellerperms,
97 | 'all' => \$all,
98 | 'help' => \$helpME,
99 | 'useDig' => \$useDig,
100 | 'cruft' => \$cruft,
101 | 'mail' => \$mail,
102 | 'scan' => \$scan,
103 | 'skipquota' => \$skipquota,
104 | 'skipfind' => \$skipfind,
105 | 'q' => \$clearscreen,
106 | 'nocode' => \$nocodeblock,
107 | );
108 |
109 | if ($skipquota) {
110 | $skipquota = 1;
111 | }
112 | if ($skipfind) {
113 | $skipfind = 1;
114 | }
115 |
116 | if ($clearscreen) {
117 | system("clear");
118 | }
119 | print "\n" unless ($nocodeblock);
120 | print BOLD BLUE "acctinfo - Version: " . YELLOW $VERSION . "\n";
121 | if ($helpME) {
122 | &Usage;
123 | }
124 |
125 | my $conf = Cpanel::Config::LoadWwwAcctConf::loadwwwacctconf();
126 | my $HOMEDIR = $conf->{'HOMEDIR'};
127 | my $HOMEMATCH = $conf->{'HOMEMATCH'};
128 | my $SERVER_IP = $conf->{'ADDR'};
129 | my $cpconf = Cpanel::Config::LoadCpConf::loadcpconf();
130 | my $DBPrefix = $cpconf->{'database_prefix'};
131 |
132 | my ( $os_release, $os_ises ) = get_release_version();
133 |
134 | my $IS_USERNAME = 1;
135 |
136 | my $QUERY = @ARGV[0];
137 | chomp($QUERY);
138 | if ( $QUERY eq "" ) {
139 | &Usage;
140 | }
141 | $QUERY = lc($QUERY);
142 | if ( index( $QUERY, '.' ) != -1 ) {
143 | $IS_USERNAME = 0;
144 | }
145 |
146 | my $HOSTNAME = Cpanel::Sys::Hostname::gethostname();
147 | my $MAINDOMAIN = "";
148 | my $username = "";
149 |
150 | if ($IS_USERNAME) {
151 | $MAINDOMAIN = FindMainDomain($QUERY);
152 | $username = $QUERY;
153 | }
154 | else {
155 | $username = FindUser($QUERY);
156 | $MAINDOMAIN = FindMainDomain($username);
157 | }
158 | chomp($MAINDOMAIN);
159 | chomp($username);
160 | if ( !($MAINDOMAIN) ) {
161 | $username = FindUser($QUERY);
162 | $MAINDOMAIN = FindMainDomain($username);
163 | }
164 |
165 | # If both variables are still empty, neither the username nor the domain name were found!
166 | if ( $MAINDOMAIN eq "" and $username eq "" ) {
167 | if ($cruft) {
168 | &cruft_check;
169 | }
170 | print
171 | "Error - $QUERY not found on $HOSTNAME (or missing from /etc/userdomains file)\n";
172 | print "Try using the --cruft switch (acctinfo $QUERY --cruft)\n";
173 | print "\n" unless ($nocodeblock);
174 | exit;
175 | }
176 |
177 | if ($scan) {
178 | &scan;
179 | exit;
180 | }
181 |
182 | if ( $username eq "nobody" ) {
183 | print RED "[WARN] - "
184 | . YELLOW $QUERY
185 | . " has an owner of "
186 | . WHITE
187 | . "\"nobody\""
188 | . YELLOW " in /etc/userdomains!\n";
189 | exit;
190 | }
191 |
192 | # Load /var/cpanel/users/$username into config hash variable
193 | my $user_conf = Cpanel::Config::LoadCpUserFile::load($username);
194 | my $DOMAIN = $QUERY;
195 | my $IS_PARKED = "";
196 | my $IS_ADDON = "";
197 | my $IS_SUB = "";
198 | my @SUBDOMAINS = "";
199 | my @ADDONDOMAINS = "";
200 | my @PARKEDDOMAINS = "";
201 | my $ACCT = "";
202 | my $MAILBOX_FORMAT = "";
203 | my $MAXPOP = 0;
204 | my $MAX_EMAIL_PER_HOUR = 0;
205 | my $MAX_DEFER_FAIL_PERCENTAGE = 0;
206 | open( USERDATAFILE, "/etc/userdatadomains" );
207 | my @USERDATADOMAINS = ;
208 | close(USERDATAFILE);
209 |
210 | # Get all sub domains (if any)
211 | foreach $ACCT (@USERDATADOMAINS) {
212 | chomp($ACCT);
213 | if ( $ACCT =~ m/ $username=/ ) {
214 | if ( $ACCT =~ m/==sub==/ ) {
215 | my ($sub_domain) = ( split( /\s+/, $ACCT ) )[0];
216 | chop($sub_domain);
217 | push( @SUBDOMAINS, $sub_domain );
218 | if ( $sub_domain eq $DOMAIN ) {
219 |
220 | # Get documentroot for $DOMAIN from /etc/userdatadomains
221 | my ($docroot) =
222 | ( split( /==/, qx[ grep $sub_domain /etc/userdatadomains ] ) )
223 | [4];
224 | $IS_SUB =
225 | "$DOMAIN is a sub domain of $MAINDOMAIN \n\t\\_ "
226 | . YELLOW
227 | . "(DocumentRoot: "
228 | . WHITE $docroot . ")\n";
229 | }
230 | }
231 | }
232 | }
233 |
234 | # Get all addon domains (if any)
235 | foreach $ACCT (@USERDATADOMAINS) {
236 | chomp($ACCT);
237 | if ( $ACCT =~ m/ $username=/ ) {
238 | if ( $ACCT =~ m/==addon==/ ) {
239 | my ($addon_domain) = ( split( /\s+/, $ACCT ) )[0];
240 | chop($addon_domain);
241 | push( @ADDONDOMAINS, $addon_domain );
242 | if ( $addon_domain eq $DOMAIN ) {
243 |
244 | # Get documentroot for $DOMAIN from /etc/userdatadomains
245 | my ($docroot) = (
246 | split(
247 | /==/, qx[ grep $addon_domain /etc/userdatadomains ]
248 | )
249 | )[4];
250 | $IS_ADDON =
251 | "$DOMAIN is an addon domain of $MAINDOMAIN \n\t\\_ "
252 | . YELLOW
253 | . "(DocumentRoot: "
254 | . WHITE $docroot . ")\n";
255 | }
256 | }
257 | }
258 | }
259 |
260 | # Get all aliased domains (if any)
261 | foreach $ACCT (@USERDATADOMAINS) {
262 | chomp($ACCT);
263 | if ( $ACCT =~ m/ $username=/ ) {
264 | if ( $ACCT =~ m/==parked==/ ) {
265 | my ($parked_domain) = ( split( /\s+/, $ACCT ) )[0];
266 | chop($parked_domain);
267 | push( @PARKEDDOMAINS, $parked_domain );
268 | if ( $parked_domain eq $DOMAIN ) {
269 |
270 | # Get documentroot for $DOMAIN from /etc/userdatadomains
271 | my ($docroot) = (
272 | split(
273 | /==/, qx[ grep $parked_domain /etc/userdatadomains ]
274 | )
275 | )[4];
276 | $IS_PARKED =
277 | "$DOMAIN is an alias (parked) domain of $MAINDOMAIN \n\t\\_ "
278 | . YELLOW
279 | . "(DocumentRoot: "
280 | . WHITE $docroot . ")\n";
281 | }
282 | }
283 | }
284 | }
285 |
286 | shift @SUBDOMAINS;
287 | shift @ADDONDOMAINS;
288 | shift @PARKEDDOMAINS;
289 | my $subcnt = @SUBDOMAINS;
290 | my $addoncnt = @ADDONDOMAINS;
291 | my $parkcnt = @PARKEDDOMAINS;
292 |
293 | if ($cruft) {
294 | &cruft_check;
295 | }
296 |
297 | # We already have the $user_conf hash variable.
298 | my $PACKAGE = $user_conf->{'PLAN'};
299 | my $THEME = $user_conf->{'RS'};
300 | my $IPADDR = $user_conf->{'IP'};
301 | my $HAS_AUTOSSL = $user_conf->{'FEATURE-AUTOSSL'};
302 | my $BACKUPENABLED = $user_conf->{'BACKUP'};
303 | my $LEGACYBACKUP = $user_conf->{'LEGACY_BACKUP'};
304 | my $BWLIMIT = $user_conf->{'BWLIMIT'};
305 | my $MAXADDON = $user_conf->{'MAXADDON'};
306 | my $MAXPARK = $user_conf->{'MAXPARK'};
307 | my $MAXSUB = $user_conf->{'MAXSUB'};
308 | my $MAXFTP = $user_conf->{'MAXFTP'};
309 | my $MAXSQL = $user_conf->{'MAXSQL'};
310 | my $MAXLST = $user_conf->{'MAXLST'};
311 | my $FEATURELIST = $user_conf->{'FEATURELIST'};
312 | my $STARTDATE = scalar localtime( $user_conf->{'STARTDATE'} );
313 | my @ResolvedIP;
314 | my $ResolvedIP;
315 |
316 | if ( $BWLIMIT ne "unlimited" ) {
317 | $BWLIMIT = ( $BWLIMIT / 1024 ) / 1024;
318 | }
319 |
320 | if (qx[ grep 'FEATURE-AUTOSSL=0' /var/cpanel/users/$username ]) {
321 | $HAS_AUTOSSL = "Explicitly Disabled";
322 | }
323 | else {
324 | $HAS_AUTOSSL = ($HAS_AUTOSSL) ? "Yes" : "No (But see featurelist above)";
325 | }
326 | my $HAS_AUTOSSL_TEXT;
327 |
328 | #my $HAS_AUTOSSL_TEXT = "(AutoSSL enabled in \"$FEATURELIST\" feature list)";
329 |
330 | # Check disabled feature list to see if autossl=0 exists
331 | my $AutoSSL_Disabled = qx[ grep 'autossl=0' /var/cpanel/features/disabled ];
332 | if ($AutoSSL_Disabled) {
333 | $HAS_AUTOSSL_TEXT = "(AutoSSL in disabled feature list)";
334 | }
335 |
336 | # Check $FEATURELIST feature list to see if autossl=0 exists
337 | my $AutoSSL_Disabled;
338 | if ( !( -e ("/var/cpanel/features/$FEATURELIST") ) ) {
339 | $AutoSSL_Disabled = "$FEATURELIST not found in /var/cpanel/features!";
340 | $HAS_AUTOSSL_TEXT = RED "[WARN] - Missing from /var/cpanel/features/";
341 | }
342 | else {
343 | $AutoSSL_Disabled =
344 | qx[ grep 'autossl=0' /var/cpanel/features/$FEATURELIST ];
345 | if ($AutoSSL_Disabled) {
346 | $HAS_AUTOSSL_TEXT = "(AutoSSL disabled in $FEATURELIST)";
347 | }
348 | }
349 | if ( $HAS_AUTOSSL_TEXT eq "" ) {
350 | $HAS_AUTOSSL_TEXT = "(AutoSSL enabled in \"$FEATURELIST\" feature list)";
351 | }
352 |
353 | $BACKUPENABLED = ($BACKUPENABLED) ? "Yes" : "No";
354 | $LEGACYBACKUP = ($LEGACYBACKUP) ? "Yes" : "No";
355 | if ($IS_USERNAME) {
356 |
357 | # Resolve the ip address of $MAINDOMAIN to see if it is pointing somewhere else
358 | if ($useDig) {
359 | @ResolvedIP = qx[ dig \@208.67.220.220 $MAINDOMAIN A +short ];
360 | }
361 | else {
362 | @ResolvedIP = getArecords($MAINDOMAIN);
363 | }
364 | }
365 | else {
366 | # a domain name was entered so we should resolve the IP of that instead.
367 | if ($useDig) {
368 | @ResolvedIP = qx[ dig \@208.67.222.222 $DOMAIN A +short ];
369 | }
370 | else {
371 | @ResolvedIP = getArecords($DOMAIN);
372 | }
373 | }
374 | my $IPTYPE = "";
375 | if ( $IPADDR eq $SERVER_IP ) {
376 | $IPTYPE = "shared";
377 | }
378 | else {
379 | $IPTYPE = "dedicated";
380 | }
381 | my $REAL_OWNER = $user_conf->{'OWNER'};
382 | my $RO_TEXT = "";
383 | if ( $REAL_OWNER ne $username and $REAL_OWNER ne "root" ) {
384 | $RO_TEXT = " (Which is under the reseller: $REAL_OWNER)";
385 | }
386 |
387 | # Check if main domain (username) is a reseller.
388 | my @ACCTSOWNEDBYRESELLER = undef;
389 | my @SORTEDRESELLERACCTS = undef;
390 | my @LISTOFACCTS = undef;
391 | my $Is_Reseller = 0;
392 | my $ResellerAcctsCnt = 0;
393 | my $ResellerDomain = "";
394 | my $vcu_account = "";
395 | my $ResellersAcct = "";
396 | my $RESELLER = "";
397 | my $FOUND = "";
398 | my $ResellerSharedIP = "None";
399 | my @ResellerIPS = undef;
400 | my $ResellerIP = "None";
401 | my $ResellerIPS = "None";
402 | my @ALL_RESELLERS = Cpanel::ResellerFunctions::getresellerslist();
403 | unshift @ALL_RESELLERS, 'root';
404 |
405 | foreach $RESELLER (@ALL_RESELLERS) {
406 | chomp($RESELLER);
407 | if ( $RESELLER eq $username ) {
408 | $Is_Reseller = 1;
409 |
410 | # Grab resellers shared IP (if configured) from /var/cpanel/mainips/$RESELLER.
411 | if ( -e ("/var/cpanel/mainips/$RESELLER") ) {
412 | $ResellerSharedIP = qx[ cat /var/cpanel/mainips/$RESELLER ];
413 | chomp($ResellerSharedIP);
414 | }
415 | if ( -e ("/var/cpanel/dips/$RESELLER") ) {
416 | open( RESELLERIPS, "/var/cpanel/dips/$RESELLER" );
417 | @ResellerIPS = ;
418 | close(RESELLERIPS);
419 | }
420 |
421 | # Read all accounts in /var/cpanel/users into array
422 | opendir( ACCTS, "/var/cpanel/users" );
423 | my @LISTOFACCTS = readdir(ACCTS);
424 | closedir(ACCTS);
425 | foreach $vcu_account (@LISTOFACCTS) {
426 | chomp($vcu_account);
427 | if ( $vcu_account =~ m/HASH/
428 | or $vcu_account eq "."
429 | or $vcu_account eq ".." )
430 | {
431 | next;
432 | }
433 | $FOUND = "";
434 | $FOUND =
435 | qx[ grep 'OWNER=$username' /var/cpanel/users/$vcu_account ];
436 | if ($FOUND) {
437 | $ResellersAcct =
438 | qx[ grep 'DNS=' /var/cpanel/users/$vcu_account ];
439 | $ResellerDomain = substr( $ResellersAcct, 4 );
440 | chomp($ResellerDomain);
441 | push( @ACCTSOWNEDBYRESELLER, "$ResellerDomain ($vcu_account)" );
442 | }
443 | }
444 | $ResellerAcctsCnt = @ACCTSOWNEDBYRESELLER;
445 | $ResellerAcctsCnt--;
446 | last;
447 | }
448 | }
449 |
450 | my $TOTAL_DOMAINS = qx[ cat /etc/trueuserdomains | wc -l ];
451 | chomp($TOTAL_DOMAINS);
452 | print WHITE "There are "
453 | . YELLOW $TOTAL_DOMAINS
454 | . WHITE " total accounts on ("
455 | . GREEN ON_BLACK $HOSTNAME
456 | . WHITE ").\n";
457 | if ($IS_USERNAME) {
458 | print "\n";
459 | }
460 | else {
461 | print GREEN ON_BLACK "\nThe user name for "
462 | . BLUE $DOMAIN
463 | . GREEN ON_BLACK " is: "
464 | . YELLOW $username . "\n";
465 | }
466 |
467 | # Get home directory from /etc/passwd
468 | my @PASSWDS = undef;
469 | our $RealHome = "";
470 | our $SSLProvider = getSSLprovider();
471 | our $passline = "";
472 | my $RealShell = "";
473 | my $UID = "";
474 | my $GID = "";
475 | open( PASSWD, "/etc/passwd" );
476 | @PASSWDS = ;
477 | close(PASSWD);
478 |
479 | foreach $passline (@PASSWDS) {
480 | chomp($passline);
481 | if ( $passline =~ m/\b$username\b/ ) {
482 | ($UID) = ( split( /:/, $passline ) )[2];
483 | ($GID) = ( split( /:/, $passline ) )[3];
484 | ($RealHome) = ( split( /:/, $passline ) )[5];
485 | ($RealShell) = ( split( /:/, $passline ) )[6];
486 | last;
487 | }
488 | }
489 |
490 | # Check for missing hash in /etc/shadow
491 | my ($PWHash) = ( split( /:/, qx[ grep $username /etc/shadow ] ) )[1];
492 | if ( $PWHash eq "" ) {
493 | print RED "[WARN] * $username is missing password hash in /etc/shadow\n";
494 | }
495 |
496 | # Get IP address from .lastlogin file (if it exists)
497 | my $LastLoginIP = "";
498 | if ( -e ("$RealHome/.lastlogin") ) {
499 | $LastLoginIP = qx[ tail -1 $RealHome/.lastlogin ];
500 | chomp($LastLoginIP);
501 | }
502 |
503 | print GREEN ON_BLACK "The main domain is "
504 | . YELLOW $MAINDOMAIN
505 | . GREEN ON_BLACK $RO_TEXT . "\n";
506 |
507 | if ( $MAINDOMAIN eq $HOSTNAME ) {
508 | print RED "[WARN] - $MAINDOMAIN is the same as hostname $HOSTNAME!\n";
509 | }
510 | if ( $QUERY eq $HOSTNAME ) {
511 | print RED "[WARN] - $QUERY is the same as hostname $HOSTNAME!\n";
512 | }
513 |
514 | # Get docroot for MAINDOMAIN too.
515 | my ($maindocroot) =
516 | ( split( /==/, qx[ grep '^$MAINDOMAIN' /etc/userdatadomains ] ) )[4];
517 | print "\t\\_ " . YELLOW . "(DocumentRoot: " . WHITE $maindocroot . ")\n";
518 |
519 | print WHITE "Real Home Directory (/etc/passwd): " . CYAN $RealHome ;
520 |
521 | # Perm check - make sure $RealHome is 711 - Warn if not!
522 | if ( -e ("$RealHome") ) {
523 | my $statmode = ( stat($RealHome) )[2] & 07777;
524 | $statmode = sprintf "%lo", $statmode;
525 | if ( $statmode != 711 ) {
526 | print RED " - [WARN] - $RealHome permissions are not 711 [$statmode]\n";
527 | print YELLOW
528 | "(Seeing require_files: permission denied errors in /var/log/exim_mainlog? - This may be why)\n";
529 | }
530 | }
531 | print "\n";
532 |
533 | # Check if user is in demo mode
534 | my $InDemo = qx[ grep $username /etc/demousers /etc/demodomains];
535 | if ($InDemo) {
536 | print RED "[WARN] - $username is in demo mode!\n";
537 | }
538 |
539 | # Check if bandwidth limit exceeded
540 | if ( -e ("/var/cpanel/bwlimited/$username")
541 | or -e ("/var/cpanel/bwlimited/$MAINDOMAIN")
542 | or -e ("/var/cpanel/bwlimited/$QUERY") )
543 | {
544 | print RED
545 | "[WARN] - $MAINDOMAIN ($username) may have exceeded their bandwidth limit!\n";
546 | my ($bwused) =
547 | qx[ uapi --user=$username StatsBar get_stats display=bandwidthusage | grep 'count:' | grep -v '_count' ];
548 | chomp($bwused);
549 | my ($bwmax) =
550 | qx[ uapi --user=$username StatsBar get_stats display=bandwidthusage | grep 'max:' | grep -v '_max' ];
551 | chomp($bwmax);
552 | $bwused =~ s/count://g;
553 | $bwmax =~ s/max://g;
554 | $bwused = alltrim($bwused);
555 | $bwmax = alltrim($bwmax);
556 | print "\t \\_ $bwused / $bwmax\n";
557 | }
558 | if ($Is_Reseller) {
559 | print GREEN ON_BLACK "This account is also a reseller!\n";
560 | if ($ResellerSharedIP) {
561 | print GREEN "Reseller's Shared IP: " . WHITE $ResellerSharedIP . "\n";
562 | }
563 | if (@ResellerIPS) {
564 | print GREEN "Reseller's IP Delegation\n";
565 | foreach $ResellerIP (@ResellerIPS) {
566 | chomp($ResellerIP);
567 | if ( $ResellerIP ne "" ) {
568 | print YELLOW "\t \\_ $ResellerIP\n";
569 | }
570 | else {
571 | print YELLOW "\t \\_ Open Delegation "
572 | . CYAN
573 | . "(any IP on this server can be used by "
574 | . WHITE $username
575 | . CYAN . ")\n";
576 | }
577 | }
578 | }
579 | else {
580 | print GREEN "Reseller's IP Delegation: ";
581 | print YELLOW "Open Delegation "
582 | . CYAN
583 | . "(any IP on this server can be used by "
584 | . WHITE $username
585 | . CYAN . ")\n";
586 | }
587 | }
588 | print GREEN "$IS_PARKED\n" unless ( $IS_PARKED eq "" );
589 | print GREEN "$IS_ADDON\n" unless ( $IS_ADDON eq "" );
590 | print GREEN "$IS_SUB\n" unless ( $IS_SUB eq "" );
591 | print WHITE "Shell: " . CYAN $RealShell . "\n";
592 | &ChkForIntegration;
593 |
594 | # check if user is in /etc/ftpusers
595 | my $ftpblock = "";
596 | if ( -e ("/etc/ftpusers") ) {
597 | $ftpblock = qx[ grep $username /etc/ftpusers ];
598 | if ($ftpblock) {
599 | print RED
600 | "[WARN] - $username found in /etc/ftpusers file (FTP authentication will fail!\n";
601 | }
602 | }
603 | print WHITE "UID/GID: " . CYAN $UID . "/" . $GID;
604 | my $UID_MIN = qx[ grep 'UID_MIN' /etc/login.defs ];
605 | my $GID_MIN = qx[ grep 'GID_MIN' /etc/login.defs ];
606 | ($UID_MIN) = ( split( /\s+/, $UID_MIN ) )[1];
607 | ($GID_MIN) = ( split( /\s+/, $GID_MIN ) )[1];
608 | $UID_MIN = alltrim($UID_MIN);
609 | $GID_MIN = alltrim($GID_MIN);
610 |
611 | #if ( version_compare( $os_release, qw( > 6.9 ) ) ) {
612 | if ( $UID < $UID_MIN or $GID < $GID_MIN ) {
613 | print RED " - [WARN] - UID/GID is less than $UID_MIN/$GID_MIN\n";
614 | }
615 | else {
616 | print "\n";
617 | }
618 |
619 | # New get quota info from uapi
620 | #my ($quotaused) =
621 | #qx[ uapi --user=$username StatsBar get_stats display=diskusage | grep 'count:' | grep -v '_count' ];
622 | #chomp($quotaused);
623 | #my ($maxquota) =
624 | #qx[ uapi --user=$username StatsBar get_stats display=diskusage | grep 'max:' | grep -v '_max' ];
625 | #chomp($maxquota);
626 | #$quotaused =~ s/count://g;
627 | #$maxquota =~ s/max://g;
628 | #$quotaused = alltrim($quotaused);
629 | #$maxquota = alltrim($maxquota);
630 | # Even newer, use whmapi1 (seems to be faster)
631 | my $quotaused =
632 | alltrim(qx[ whmapi1 accountsummary user=$username | grep 'diskused:' ]);
633 | ($quotaused) = ( split( /\s+/, $quotaused ) )[1];
634 | my $maxquota =
635 | alltrim(qx[ whmapi1 accountsummary user=$username | grep 'disklimit' ]);
636 | ($maxquota) = ( split( /\s+/, $maxquota ) )[1];
637 | print "Disk Quota: $quotaused used of $maxquota allowed\n";
638 |
639 | # Check if account is over quota, warn if so, unless --skipquota is passed.
640 | # -s human-readable, -l local only (ignore NFS), -q quiet
641 | # check if the account is over quota (slq does this, if nothing returned, it's not over quota.
642 | if ( $skipquota == 0 ) {
643 | open( QUOTACHK, "/usr/bin/quota -slq $username 2> /dev/null |" );
644 | my @quotachk = ;
645 | close(QUOTACHK);
646 | my $BlockLimitReached;
647 | my $quotaused;
648 | my $quotaallowed;
649 | foreach $BlockLimitReached (@quotachk) {
650 | chomp($BlockLimitReached);
651 | if ( $BlockLimitReached =~ m/Block limit reached on / ) {
652 | print RED "[WARN] - $username is over quota ";
653 | my ($quotadev) = ( split( /\s+/, $BlockLimitReached ) )[5];
654 | my $quotaHR1 = qx[ grep $quotadev /etc/mtab ];
655 | my ($quotaHR) = ( split( /\s+/, $quotaHR1 ) )[1];
656 | ( $quotaused, $quotaallowed ) = (
657 | split(
658 | /\s+/,
659 | qx[ /usr/bin/quota -sl $username | egrep -v 'Filesystem|quotas' | tail -1 ]
660 | )
661 | )[ 2, 3 ];
662 | print
663 | "($quotadev [$quotaHR] is over quota [$quotaused/$quotaallowed])\n";
664 | }
665 | }
666 | }
667 |
668 | if ( !( -e ("/var/cpanel/features/$FEATURELIST") ) ) {
669 | print YELLOW
670 | "[INFO] - Skipping bandwidth check! Feature list \"$FEATURELIST\" missing from /var/cpanel/features/\n";
671 | }
672 | else {
673 | my ($bwused) =
674 | qx[ uapi --user=$username StatsBar get_stats display=bandwidthusage | grep 'count:' | grep -v '_count' ];
675 | chomp($bwused);
676 | my ($bwmax) =
677 | qx[ uapi --user=$username StatsBar get_stats display=bandwidthusage | grep 'max:' | grep -v '_max' ];
678 | chomp($bwmax);
679 | $bwused =~ s/count://g;
680 | $bwmax =~ s/max://g;
681 | $bwused = alltrim($bwused);
682 | $bwmax = alltrim($bwmax);
683 | print "Bandwidth: $bwused used of $bwmax allowed\n";
684 | }
685 |
686 | # Check for custom style (Paper Lantern Theme)
687 | my $custom_style_path = "$RealHome/var/cpanel/styled/current_style";
688 | my $custom_style_link;
689 | my $custom_style;
690 | my @custom_style_array;
691 | my $custom_style_array;
692 | if ( -e ("$custom_style_path") ) {
693 | $custom_style_link = readlink($custom_style_path);
694 | @custom_style_array = split( "\/", $custom_style_link );
695 | $custom_style = $custom_style_array[-1];
696 | }
697 |
698 | print WHITE "Hosting Package: "
699 | . CYAN $PACKAGE
700 | . WHITE " ("
701 | . "Feature List: "
702 | . GREEN $FEATURELIST
703 | . WHITE ") "
704 | . $HAS_AUTOSSL_TEXT . "\n";
705 | my $X3WARN = "";
706 | if ( $THEME eq "x3" ) {
707 | $X3WARN = RED
708 | "[WARN] - x3 Theme deprecated. cPanel UI not loading? This is probably why!";
709 | }
710 | if ($custom_style) {
711 | print WHITE "Theme: "
712 | . CYAN $THEME
713 | . " (Style: $custom_style) "
714 | . $X3WARN . "\n";
715 | }
716 | else {
717 | print WHITE "Theme: " . CYAN $THEME . " " . $X3WARN . "\n";
718 | }
719 | print WHITE "Max Addon/Alias/Sub Domains: "
720 | . CYAN $MAXADDON
721 | . WHITE " / "
722 | . CYAN $MAXPARK
723 | . WHITE " / "
724 | . CYAN $MAXSUB . "\n";
725 | print WHITE "Max SQL Databases: " . CYAN $MAXSQL . "\n";
726 | print WHITE "Max Mailman Lists: " . CYAN $MAXLST . "\n";
727 | print WHITE "Max FTP Accounts: " . CYAN $MAXFTP . "\n";
728 | print WHITE "Max Bandwidth Allowed: " . CYAN $BWLIMIT . " MB\n";
729 | print WHITE "AutoSSL Enabled: " . CYAN $HAS_AUTOSSL . "\n";
730 | print WHITE "Backup Enabled: "
731 | . CYAN $BACKUPENABLED
732 | . GREEN " / "
733 | . WHITE "LEGACY: "
734 | . CYAN $LEGACYBACKUP . "\n";
735 |
736 | my $PHPDefaultVersion;
737 | my $PHPversion;
738 | my $isEA4 = 0;
739 | my $cageFSStats = &check_for_cagefs();
740 | if ($cageFSStats) {
741 | print WHITE "CageFS: " . CYAN $cageFSStats . "\n";
742 |
743 | # See if /home/$username/.cl.selector/defaults.cfg is present. If so grab PHP Version from it.
744 | }
745 | else {
746 | print WHITE "CageFS: " . CYAN . "Not installed!\n";
747 | }
748 |
749 | # Check for php-selector (CloudLinux)
750 | my $clPHPVer = 0;
751 | if ( -e ("$RealHome/.cl.selector/defaults.cfg") and $cageFSStats eq "Enabled" )
752 | {
753 | my $clPHP = qx[ egrep '^php' $RealHome/.cl.selector/defaults.cfg ];
754 | $clPHPVer =~ s/\s+//g;
755 | ($clPHPVer) = ( split( /=/, $clPHP ) )[1];
756 | chomp($clPHPVer);
757 | $clPHPVer = alltrim($clPHPVer);
758 | if ($clPHPVer) {
759 | print WHITE "CloudLinux PHP Version: " . CYAN $clPHPVer . "\n";
760 |
761 | my $PHPiniFile =
762 | qx[ su -s /bin/bash $username -c "php -i | grep '^Configuration File'" ];
763 | my $PHPiniLoad =
764 | qx[ su -s /bin/bash $username -c "php -i | grep '^Loaded Configuration File'" ];
765 | my $PHPiniScan =
766 | qx[ su -s /bin/bash $username -c "php -i | grep '^Scan this dir'" ];
767 | chomp($PHPiniFile);
768 | chomp($PHPiniLoad);
769 | chomp($PHPiniScan);
770 | if ( $cageFSStats and $cageFSStats eq "Enabled" ) {
771 | print YELLOW "\t \\_ $PHPiniFile\n";
772 | print YELLOW "\t \\_ $PHPiniLoad\n";
773 | print YELLOW "\t \\_ $PHPiniScan\n";
774 | }
775 | }
776 | }
777 |
778 | my $skipEA4 = 0;
779 | if ( $clPHPVer and $cageFSStats eq "Enabled" ) {
780 | $skipEA4 = 1;
781 | }
782 |
783 | $isEA4 = &isEA4;
784 | my $clPHPActive = 0;
785 | if ( $isEA4 and !$skipEA4 ) {
786 | $PHPDefaultVersion = &get_system_php_version();
787 | if ( $PHPDefaultVersion eq "" ) {
788 | $PHPDefaultVersion = "UNKNOWN";
789 | }
790 | $PHPversion = &get_php_version();
791 | if ( $PHPversion eq "" ) {
792 | $PHPversion = "inherit";
793 | }
794 | if ( $PHPversion eq "inherit" ) { $clPHPActive = 1; }
795 | print WHITE "[EA4] PHP Version: "
796 | . CYAN $PHPversion
797 | . " (System Default: $PHPDefaultVersion) ";
798 |
799 | # Check for ^suPHP_ConfigPath variable in .htaccess files
800 | my $suPHPConfPathFound;
801 | if ( -e ("$RealHome/public_html/.htaccess") ) {
802 | $suPHPConfPathFound =
803 | qx[ egrep '^suPHP_ConfigPath' "$RealHome/public_html/.htaccess" ];
804 | }
805 |
806 | if ( $clPHPActive and $cageFSStats eq "Enabled" ) {
807 | print MAGENTA "CloudLinux PHP Version has precedence\n";
808 | }
809 | else {
810 | print MAGENTA "cPanel EA4 PHP Version has precedence\n";
811 | }
812 | if ( -e ("/var/cpanel/userdata/$username/$MAINDOMAIN.php-fpm.yaml") ) {
813 | print YELLOW "PHP-FPM pool detected\n";
814 | }
815 |
816 | # Get php.ini config info
817 | if ( $PHPversion eq "inherit" and $cageFSStats ne "Enabled" ) {
818 | $PHPversion = $PHPDefaultVersion;
819 | }
820 | if ( -e ("/etc/scl/conf/$PHPversion")
821 | or ( -e ("/etc/scl/prefixes/$PHPversion") ) )
822 | {
823 | my $PHPiniFile =
824 | qx[ /usr/bin/scl enable $PHPversion "php -i" | grep '^Configuration File' ];
825 | my $PHPiniLoad =
826 | qx[ /usr/bin/scl enable $PHPversion "php -i" | grep '^Loaded Configuration File' ];
827 | my $PHPiniScan =
828 | qx[ /usr/bin/scl enable $PHPversion "php -i" | grep '^Scan this dir' ];
829 |
830 | if ($suPHPConfPathFound) {
831 | print YELLOW "[NOTE]"
832 | . WHITE
833 | . " - suPHP_ConfigPath found in "
834 | . CYAN
835 | . $suPHPConfPathFound;
836 | my ($UsersuPHPConfPath) =
837 | ( split( /\s+/, $suPHPConfPathFound ) )[1];
838 | $PHPiniFile =
839 | "Configuration File (php.ini) Path => $UsersuPHPConfPath";
840 | $PHPiniLoad = "Loaded Configuration File => $UsersuPHPConfPath";
841 | $PHPiniScan = "Scan this dir for additional .ini files => None";
842 | }
843 | chomp($PHPiniFile);
844 | chomp($PHPiniLoad);
845 | chomp($PHPiniScan);
846 | print YELLOW "\t \\_ $PHPiniFile\n";
847 | print YELLOW "\t \\_ $PHPiniLoad\n";
848 | print YELLOW "\t \\_ $PHPiniScan\n";
849 | }
850 |
851 | if ( !( -e ("$RealHome/public_html") ) ) {
852 | $skipfind = 1;
853 | }
854 |
855 | # Search /home/username for any php.ini files and/or .user.ini files (unless --skipfind)
856 | if ( $skipfind == 0 ) {
857 | my @customPHPINI =
858 | qx[ find $RealHome/public_html -maxdepth 1 -name 'php.ini' ];
859 | my @customuserINI =
860 | qx[ find $RealHome/public_html -maxdepth 1 -name '.user.ini' ];
861 | my $customPHPINIfile;
862 | my $customuserINIfile;
863 | if (@customPHPINI) {
864 | print GREEN "Custom php.ini file found in: \n";
865 | foreach $customPHPINIfile (@customPHPINI) {
866 | chomp($customPHPINIfile);
867 | print YELLOW "\t \\_ $customPHPINIfile\n";
868 | }
869 | }
870 | if (@customuserINI) {
871 | print GREEN "Custom .user.ini file found in: \n";
872 | foreach $customuserINIfile (@customuserINI) {
873 | chomp($customuserINIfile);
874 | print YELLOW "\t \\_ $customuserINIfile\n";
875 | }
876 | }
877 | print "\n";
878 | }
879 | }
880 |
881 | my $IS_IP_ON_SERVER = qx[ ip addr | grep $IPADDR ];
882 | my $NOTONSERVER = "[ Is configured on this server ] ";
883 | if ( $IS_IP_ON_SERVER eq "" ) {
884 | $NOTONSERVER = "[ Not configured on this server ]";
885 | }
886 | print WHITE "IP address: "
887 | . CYAN $IPADDR
888 | . WHITE " ("
889 | . CYAN $IPTYPE
890 | . WHITE ") - $NOTONSERVER\n";
891 | my $defaultsite = 0;
892 | my $TotalARecords = @ResolvedIP;
893 | my $ConnectionTimeout = 0;
894 | if ( @ResolvedIP[4] =~ m/no servers could be reached/ ) {
895 | $TotalARecords = 0;
896 | $ConnectionTimeout = 1;
897 | }
898 | my $ResolvesToDetail = "";
899 | print WHITE "Resolves to IP: ";
900 | if ( $TotalARecords > 1 ) {
901 | print "(multiple A records found) \n";
902 | foreach $ResolvedIP (@ResolvedIP) {
903 | chomp($ResolvedIP);
904 | $ResolvesToDetail = &check_resolved_ip($ResolvedIP);
905 | print CYAN "\t \\_" . $ResolvedIP . " " . RED $ResolvesToDetail . "\n";
906 | }
907 | }
908 | else { ## ONLY 1 A RECORED RETURNED.
909 | $ResolvedIP = @ResolvedIP[0];
910 | chomp($ResolvedIP);
911 | if ($ConnectionTimeout) {
912 | $ResolvedIP = "";
913 | }
914 | if ( $TotalARecords == 0 and $ResolvedIP eq "" ) {
915 | print "DOES NOT RESOLVE!\n";
916 | $defaultsite = 1;
917 | }
918 | else {
919 | $ResolvesToDetail = &check_resolved_ip($ResolvedIP);
920 | print CYAN $ResolvedIP . " " . RED $ResolvesToDetail;
921 | }
922 | print "\n";
923 | }
924 |
925 | if ($defaultsite) {
926 | print YELLOW
927 | "Not seeing the site you're expecting (or defaultwebpage.cgi)? - This may be why!\n";
928 | }
929 |
930 | if ( $all or $mail ) {
931 | &display_mail_info;
932 | }
933 |
934 | # Last Login IP
935 | if ($LastLoginIP) {
936 | print WHITE "Last logged in to cPanel from IP: " . CYAN $LastLoginIP . "\n";
937 | }
938 |
939 | print WHITE "Has been a customer since " . CYAN $STARTDATE . "\n";
940 |
941 | # Check to see if the $username is in /var/cpanel/suspended directory
942 | my $SUSP = 0;
943 | my $REASON = "";
944 | if ( -e ("/var/cpanel/suspended/$username") ) {
945 | $REASON = `cat /var/cpanel/suspended/$username`;
946 | chomp($REASON);
947 | $SUSP = 1;
948 | }
949 | print WHITE "Suspended: ";
950 | if ($SUSP) {
951 | print RED "YES!";
952 | print WHITE " - Reason: " . CYAN $REASON unless ( $REASON eq "" );
953 | }
954 | else {
955 | print GREEN "No";
956 | }
957 | print "\n";
958 | print WHITE "Count of other domains: ["
959 | . YELLOW "SUB: "
960 | . GREEN $subcnt
961 | . WHITE "] - ["
962 | . YELLOW "ALIASES "
963 | . GREEN $parkcnt
964 | . WHITE "] - ["
965 | . YELLOW "ADDONS: "
966 | . GREEN $addoncnt
967 | . WHITE "]\n";
968 | &border;
969 |
970 | # END OF BASIC INFORMATION (no switches were added)
971 | # ADDITIONAL INFORMATION STARTS HERE! (if all or any other switches were added)
972 |
973 | # DOMAIN INFO (ALIASES, ADDON, SUB)
974 | my $SUB = "";
975 | my $PARK = "";
976 | my $ADDON = "";
977 | if ( $subcnt + $addoncnt + $parkcnt > 1
978 | and ( $all or $listsubs or $listaddons or $listparked or $listaliased ) )
979 | {
980 | print WHITE "The following are associated with "
981 | . CYAN $MAINDOMAIN
982 | . WHITE " ("
983 | . GREEN $username
984 | . WHITE ")\n";
985 | &smborder;
986 | }
987 | if ( $all or $listsubs ) {
988 | print YELLOW "Sub Domains: ";
989 | if ( $subcnt > 0 and ( $all or $listsubs ) ) {
990 | print "\n";
991 | foreach $SUB (@SUBDOMAINS) {
992 | chomp($SUB);
993 | print YELLOW "\t \\_ $SUB\n";
994 | }
995 | }
996 | else {
997 | print MAGENTA "No Sub Domains found for "
998 | . CYAN $MAINDOMAIN
999 | . WHITE " ("
1000 | . GREEN $username
1001 | . WHITE ")\n";
1002 | }
1003 | &smborder;
1004 | }
1005 |
1006 | if ( $all or $listaddons ) {
1007 | print YELLOW "Addon Domains: ";
1008 | if ( $addoncnt > 0 and ( $all or $listaddons ) ) {
1009 | print "\n";
1010 | foreach $ADDON (@ADDONDOMAINS) {
1011 | chomp($ADDON);
1012 | print YELLOW "\t \\_ $ADDON\n";
1013 | }
1014 | }
1015 | else {
1016 | print MAGENTA "No Addon Domains found for "
1017 | . CYAN $MAINDOMAIN
1018 | . WHITE " ("
1019 | . GREEN $username
1020 | . WHITE ")\n";
1021 | }
1022 | &smborder;
1023 | }
1024 |
1025 | if ( $all or $listparked or $listaliased ) {
1026 | print YELLOW "Aliased Domains: ";
1027 | if ( $parkcnt > 0 and ( $all or $listparked or $listaliased ) ) {
1028 | print "\n";
1029 | foreach $PARK (@PARKEDDOMAINS) {
1030 | chomp($PARK);
1031 | print YELLOW "\t \\_ $PARK\n";
1032 | }
1033 | }
1034 | else {
1035 | print MAGENTA "No Aliased Domains found for "
1036 | . CYAN $MAINDOMAIN
1037 | . WHITE " ("
1038 | . GREEN $username
1039 | . WHITE ")\n";
1040 | }
1041 | &smborder;
1042 | }
1043 |
1044 | # RESELLER INFO
1045 | if ( $reselleraccts or $all ) {
1046 | if ($all) { &border; }
1047 | my $owned_by_reseller = "";
1048 | if ( $Is_Reseller and $ResellerAcctsCnt > 0 ) {
1049 | print CYAN $MAINDOMAIN
1050 | . WHITE
1051 | " is a reseller and has the following ($ResellerAcctsCnt) accounts under it\n";
1052 | shift @ACCTSOWNEDBYRESELLER;
1053 | my @SORTEDRESELLERACCTS = sort(@ACCTSOWNEDBYRESELLER);
1054 | foreach $owned_by_reseller (@SORTEDRESELLERACCTS) {
1055 | chomp($owned_by_reseller);
1056 | print BOLD YELLOW ON_BLACK "\t \\_ $owned_by_reseller\n";
1057 | }
1058 | &border;
1059 | }
1060 | else {
1061 | print WHITE "No Reseller accounts found for "
1062 | . CYAN $MAINDOMAIN
1063 | . WHITE " ("
1064 | . GREEN $username
1065 | . WHITE ")\n";
1066 | &border;
1067 | }
1068 | }
1069 |
1070 | if ( $resellerperms or $all ) {
1071 | if ($all) { &border; }
1072 | my $DefaultPerm = "";
1073 | my $defaultRPerm = "";
1074 | my @defaultperms =
1075 | qw( acct-summary basic-system-info basic-whm-functions cors-proxy-get cpanel-api cpanel-integration create-user-session digest-auth generate-email-config list-pkgs manage-api-tokens manage-dns-records manage-oidc manage-styles mysql-info ns-config public-contact ssl-info track-email );
1076 | if ($Is_Reseller) {
1077 | open( RESELLERS, "/var/cpanel/resellers" );
1078 | my @RESELLERS = ;
1079 | close(RESELLERS);
1080 | my $resellerline = "";
1081 | my @rperms = undef;
1082 | my $rperm = "";
1083 | print CYAN "The reseller " . $MAINDOMAIN
1084 | . WHITE " has the following reseller permissions\n";
1085 | foreach $resellerline (@RESELLERS) {
1086 | chomp($resellerline);
1087 | my ( $reseller, $rperms ) = ( split( /:/, $resellerline ) );
1088 | if ( $reseller eq $username ) {
1089 | my @rperms = split /,/, $rperms;
1090 | foreach $rperm (@rperms) {
1091 | chomp($rperm);
1092 | foreach $defaultRPerm (@defaultperms) {
1093 | chomp($defaultRPerm);
1094 | if ( $rperm =~ $defaultRPerm ) {
1095 | $DefaultPerm = BLUE ON_BLACK "[DEFAULT]";
1096 | last;
1097 | }
1098 | else {
1099 | $DefaultPerm = "";
1100 | }
1101 | }
1102 | print BOLD YELLOW ON_BLACK "\t \\_ $rperm " . $DefaultPerm;
1103 | if ( $rperm eq "all" ) {
1104 | print RED "[WARN] - HAS ROOT PRIVILEGES!!!\n";
1105 | }
1106 | else {
1107 | print "\n";
1108 | }
1109 | }
1110 | }
1111 | }
1112 | &border;
1113 | }
1114 | }
1115 |
1116 | # MySQL INFO
1117 | if ( $listdbs or $all ) {
1118 | my @USERDBS = undef;
1119 | my @DBSIZE = undef;
1120 | my $USERDB = "";
1121 | my $SIZEOFDB = "";
1122 | my $DBNAME = "";
1123 | my $DBSIZE = "";
1124 |
1125 | # MySQL username can only be the first 8 characters of $usrename
1126 | my $first8;
1127 | if ($DBPrefix) {
1128 | $first8 = substr( $username, 0, 8 );
1129 | @USERDBS = qx[ echo "SHOW DATABASES like '$first8%'" | mysql -BN ];
1130 | }
1131 | else {
1132 | @USERDBS =
1133 |
1134 | # THIS BELOW FAILS IF DB PREFIX IS OFF!!!
1135 | qx[ echo "SHOW DATABASES like = '$username%'" | mysql -BN ];
1136 | }
1137 | my $DBCNT = @USERDBS;
1138 | if ( $DBCNT == 0 ) {
1139 | print WHITE "No MySQL databases found for "
1140 | . CYAN $MAINDOMAIN
1141 | . WHITE " ("
1142 | . GREEN $username
1143 | . WHITE ")\n";
1144 | }
1145 | else {
1146 | print WHITE
1147 | "The following ($DBCNT) MySQL databases can be found under: "
1148 | . GREEN $username . "\n";
1149 | foreach $USERDB (@USERDBS) {
1150 | chomp($USERDB);
1151 | $USERDB =~ s/\\//g;
1152 | print YELLOW "\t \\_ " . $USERDB . "\n";
1153 | }
1154 | }
1155 | &smborder;
1156 |
1157 | # PostGreSQL INFO
1158 | my $psql_running = 0;
1159 | if (qx[ ps ax | grep postgres | grep -v grep ]) { $psql_running = 1; }
1160 | if ( -e ("/usr/bin/psql") and $psql_running )
1161 | { ## PostGreSQL is installed and running
1162 | my @PSQLDBS = undef;
1163 | my $PgDb = "";
1164 | @PSQLDBS =
1165 | qx[ /usr/bin/psql -U postgres -c "SELECT datname FROM pg_catalog.pg_database WHERE datistemplate='f' AND datname !='postgres'" | grep -v '\-' | grep -v 'datname' | grep -v ' row' ];
1166 | pop(@PSQLDBS);
1167 | my $PgDbCount = @PSQLDBS;
1168 | if ( $PgDbCount == 0 ) {
1169 | print WHITE "No PostGreSQL databases found for "
1170 | . CYAN $MAINDOMAIN
1171 | . WHITE " ("
1172 | . GREEN $username
1173 | . WHITE ")\n";
1174 | }
1175 | else {
1176 | print WHITE
1177 | "The following ($PgDbCount) PostGreSQL databases can be found under: "
1178 | . GREEN $username . "\n";
1179 | my $pg_table = "";
1180 | my @PG_TABLES = undef;
1181 | foreach $PgDb (@PSQLDBS) {
1182 | chomp($PgDb);
1183 | $PgDb = substr( $PgDb, 1 );
1184 | print YELLOW "\t \\_" . $PgDb . "\n";
1185 | }
1186 | }
1187 | }
1188 | else {
1189 | print RED "PostGreSQL server is not installed (or running) on "
1190 | . MAGENTA $HOSTNAME . "\n";
1191 | }
1192 | &border;
1193 | }
1194 |
1195 | if ( $listssls or $all ) {
1196 | if ( $CPVersion lt "11.68.0.0" ) {
1197 | &oldlistssls;
1198 | }
1199 | else {
1200 | $sslsyscertdir = "/var/cpanel/ssl/apache_tls/";
1201 | if ( -e ("$sslsyscertdir/$MAINDOMAIN/certificates") ) {
1202 | $sslsubject =
1203 | qx[ openssl x509 -in "$sslsyscertdir/$MAINDOMAIN/certificates" -subject -noout ];
1204 | $startdate =
1205 | qx[ openssl x509 -in "$sslsyscertdir/$MAINDOMAIN/certificates" -startdate -noout ];
1206 | $expiredate =
1207 | qx[ openssl x509 -in "$sslsyscertdir/$MAINDOMAIN/certificates" -enddate -noout ];
1208 | $isSelfSigned =
1209 | qx[ openssl verify "$sslsyscertdir/$MAINDOMAIN/certificates" | grep 'self signed certificate' ];
1210 |
1211 | print WHITE "SSL Certificates installed under "
1212 | . CYAN $MAINDOMAIN
1213 | . WHITE " ("
1214 | . GREEN $username
1215 | . WHITE ")\n";
1216 | &dispSSLdata($MAINDOMAIN);
1217 | print WHITE "Protecting the following Subject Alternative Names:\n";
1218 | my $SAN;
1219 | my @getSANS =
1220 | qx[ openssl x509 -in "$sslsyscertdir/$MAINDOMAIN/certificates" -noout -text | grep -oP '(?<=DNS:)[a-z0-9.-]+' ];
1221 |
1222 | foreach $SAN (@getSANS) {
1223 | chomp($SAN);
1224 | print YELLOW "\t \\_ " . CYAN $SAN . "\n";
1225 | }
1226 | }
1227 | else {
1228 | print YELLOW $MAINDOMAIN . "\n";
1229 | print WHITE "\t \\_ " . CYAN . "No SSL found.\n";
1230 | }
1231 |
1232 | foreach $SUB (@SUBDOMAINS) {
1233 | chomp($SUB);
1234 | if ( -e ("$sslsyscertdir/$SUB/certificates") ) {
1235 | $sslsubject =
1236 | qx[ openssl x509 -in "$sslsyscertdir/$SUB/certificates" -subject -noout ];
1237 | $startdate =
1238 | qx[ openssl x509 -in "$sslsyscertdir/$SUB/certificates" -startdate -noout ];
1239 | $expiredate =
1240 | qx[ openssl x509 -in "$sslsyscertdir/$SUB/certificates" -enddate -noout ];
1241 | $isSelfSigned =
1242 | qx[ openssl verify "$sslsyscertdir/$SUB/certificates" | grep 'self signed certificate' ];
1243 | &dispSSLdata($SUB);
1244 | print WHITE
1245 | "Protecting the following Subject Alternative Names:\n";
1246 | my $SAN;
1247 | my @getSANS =
1248 | qx[ openssl x509 -in "$sslsyscertdir/$SUB/certificates" -noout -text | grep -oP '(?<=DNS:)[a-z0-9.-]+' ];
1249 |
1250 | foreach $SAN (@getSANS) {
1251 | chomp($SAN);
1252 | print YELLOW "\t \\_ " . CYAN $SAN . "\n";
1253 | }
1254 | }
1255 | else {
1256 | print YELLOW $SUB . "\n";
1257 | print WHITE "\t \\_ " . CYAN . "No SSL found.\n";
1258 | }
1259 | }
1260 |
1261 | # Check for pending AutoSSL orders here (uses whmapi1 get_autossl_pending_queue (62.0.26+ only)
1262 | if ( $SSLProvider eq "cPanel (Powered by Comodo)" ) {
1263 | print "\nChecking for pending AutoSSL orders: \n";
1264 | my $SSL_PENDING =
1265 | qx[ whmapi1 get_autossl_pending_queue | grep -B3 'user: $username' ];
1266 | if ($SSL_PENDING) {
1267 | my $NEW_SSL_PENDING;
1268 | ( $NEW_SSL_PENDING = $SSL_PENDING ) =~
1269 | s/order_item_id: /order_item_id: https:\/\/manage2.cpanel.net\/certificate.cgi\?oii=/g;
1270 | $SSL_PENDING = $NEW_SSL_PENDING;
1271 | print GREEN "\t \\_ \n";
1272 | print GREEN "$SSL_PENDING";
1273 | }
1274 | else {
1275 | print GREEN "\t \\_ None";
1276 | }
1277 | print "\n";
1278 | }
1279 |
1280 | # Check for purchased SSL's
1281 | print "Checking for pending SSL Orders (non-autossl): \n";
1282 | if ( -e ("$RealHome/.cpanel/ssl/pending_queue.json") ) {
1283 | my ($PendingSSLOrder) = (
1284 | split(
1285 | /\s+/,
1286 | qx[ python -mjson.tool $RealHome/.cpanel/ssl/pending_queue.json|grep -A1 cPStore ]
1287 | )
1288 | )[3];
1289 | $PendingSSLOrder =~ s/\"//g;
1290 | $PendingSSLOrder =~ s/,//g;
1291 | $PendingSSLOrder =~ s/://g;
1292 | print CYAN "\t \\_ Pending order number: " . GREEN
1293 | . "https://manage2.cpanel.net/certificate.cgi?oii=$PendingSSLOrder\n";
1294 | }
1295 | else {
1296 | print GREEN "\t \\_ None\n";
1297 | }
1298 |
1299 | # Check for CAA records here.
1300 | my @HasCAA;
1301 | print "Checking for CAA records: \n";
1302 |
1303 | #my @HasCAA = qx[ dig $MAINDOMAIN caa +short ];
1304 | if ($IS_USERNAME) {
1305 | @HasCAA = qx[ dig +noall +answer $MAINDOMAIN CAA | grep -v CNAME ];
1306 | }
1307 | else {
1308 | @HasCAA = qx[ dig +noall +answer $QUERY CAA | grep -v CNAME ];
1309 | }
1310 | my $CAARecord;
1311 | if (@HasCAA) {
1312 | if ($IS_USERNAME) {
1313 | print YELLOW
1314 | "[NOTE] * CAA records were found for $MAINDOMAIN\n";
1315 | }
1316 | else {
1317 | print YELLOW "[NOTE] * CAA records were found for $QUERY\n";
1318 | }
1319 | print GREEN
1320 | "SSL Certificates can only be issued from the following CA's:\n";
1321 | my ( $CAARecord1, $CAARecord2, $CAARecord3 );
1322 | foreach $CAARecord (@HasCAA) {
1323 | chomp($CAARecord);
1324 | ( $CAARecord1, $CAARecord2, $CAARecord3 ) =
1325 | ( split( /\s+/, $CAARecord ) )[ 4, 5, 6 ];
1326 | print CYAN "\t \\_ $CAARecord1 $CAARecord2 $CAARecord3\n";
1327 | }
1328 | }
1329 | else {
1330 | print GREEN "\t \\_ None\n";
1331 | }
1332 | &border;
1333 | }
1334 | }
1335 |
1336 | print "\n" unless ($nocodeblock);
1337 | exit;
1338 |
1339 | sub Usage {
1340 | print WHITE "\nUsage: "
1341 | . CYAN "acctinfo"
1342 | . WHITE " [options] domainname.tld or cPUsername [options]\n\n";
1343 | print YELLOW "Examples: \n"
1344 | . CYAN "acctinfo"
1345 | . WHITE " --listdbs somedomain.net\n";
1346 | print GREEN
1347 | "\t Lists any MySQL databases (and their sizes) as well as any PostGreSQL\n\t databases for somedomain.net\n\n";
1348 | print CYAN "acctinfo" . WHITE " --listsubs cptestdo\n";
1349 | print GREEN "\t Lists all sub domains under the cptestdo user name.\n\n";
1350 | print CYAN "acctinfo" . WHITE " --listaddons cptestdomain.net\n";
1351 | print GREEN
1352 | "\t Lists all addon domains under the cptestdomain.net domain name.\n\n";
1353 | print CYAN "acctinfo" . WHITE " --listalias cptestdomain.net\n";
1354 | print GREEN
1355 | "\t Lists all alias (parked) domains under the cptestdomain.net domain name.\n\n";
1356 | print CYAN "acctinfo" . WHITE " --reselleraccts cptestdo\n";
1357 | print GREEN
1358 | "\t Lists reseller information and domains under the cptestdo user name.\n\n";
1359 | print CYAN "acctinfo" . WHITE " --resellerperms cptestdo\n";
1360 | print GREEN
1361 | "\t Lists reseller permissions under the cptestdo user name.\n\n";
1362 | print CYAN "acctinfo" . WHITE " --listssls cptestdomain.net\n";
1363 | print GREEN
1364 | "\t Lists any SSL's under the cptestdomain.net domain name.\n\n";
1365 | print CYAN "acctinfo" . WHITE " --cruft cptestdomain.net\n";
1366 | print GREEN "\t Perform a cruft check on cptestdomain.net.\n\n";
1367 | print CYAN "acctinfo" . WHITE " --mail cptestdomain.net\n";
1368 | print GREEN "\t Display mail information for cptestdomain.net.\n\n";
1369 | print CYAN "acctinfo" . WHITE " --scan cptest\n";
1370 | print GREEN "\t Scan users home directory for known infection strings.\n\n";
1371 | print CYAN "acctinfo" . WHITE " --all cptestdomain.net\n";
1372 | print GREEN "\t Lists everything for the cptestdomain.net domain name.\n\n";
1373 | print CYAN "acctinfo" . WHITE " --help\n";
1374 | print GREEN
1375 | "\t Shows this usage information. (NOTE: [options] can go before or after domain/username).\n\n";
1376 | exit;
1377 | }
1378 |
1379 | sub border {
1380 | print MAGENTA ON_BLACK
1381 | "==============================================================================================\n";
1382 | return;
1383 | }
1384 |
1385 | sub smborder {
1386 | print MAGENTA
1387 | "----------------------------------------------------------------------------------------------\n";
1388 | return;
1389 | }
1390 |
1391 | sub FindMainDomain() {
1392 | $SearchFor = $_[0];
1393 | my $MAINUSER = "";
1394 | my $TrueUserLine = "";
1395 | open( TRUEUSER, "/etc/trueuserdomains" );
1396 | my @TRUEUSERS = ;
1397 | close(TRUEUSER);
1398 | foreach $TrueUserLine (@TRUEUSERS) {
1399 | chomp($TrueUserLine);
1400 | ( $MAINDOMAIN, $MAINUSER ) = ( split( /:\s+/, $TrueUserLine ) );
1401 | if ( $MAINUSER eq $SearchFor ) {
1402 | return $MAINDOMAIN;
1403 | }
1404 | }
1405 | }
1406 |
1407 | sub FindUser() {
1408 | my $SearchFor = $_[0];
1409 | my $UserIsReserved = isUserReserved($SearchFor);
1410 | if ($UserIsReserved) {
1411 | print RED "[WARNING] - "
1412 | . $SearchFor
1413 | . WHITE " is a reserved username!\n";
1414 | }
1415 | my $UserLine = "";
1416 | my $TheDOMAIN = "";
1417 | my $TheUSER = "";
1418 | open( USERDOMAIN, "/etc/userdomains" );
1419 | my @USERDOMAINS = ;
1420 | close(USERDOMAIN);
1421 | foreach $UserLine (@USERDOMAINS) {
1422 | chomp($UserLine);
1423 | ( $TheDOMAIN, $TheUSER ) = ( split( /:\s+/, $UserLine ) );
1424 | if ( $TheDOMAIN eq $SearchFor ) {
1425 | return $TheUSER;
1426 | }
1427 | }
1428 | }
1429 |
1430 | sub check_cloudflare_ips {
1431 | my $chkIP = $_[0];
1432 |
1433 | # Below IP's obtained from: https://www.cloudflare.com/ips
1434 | my @cf_subnets = qx[ curl -s https://www.cloudflare.com/ips-v4 ];
1435 | my $cloudflareIP = 0;
1436 | my $cf_subnet = "";
1437 | my @a = split /\./, $chkIP;
1438 | my $di = getIp(@a);
1439 | foreach $cf_subnet (@cf_subnets) {
1440 | ( $a, $b ) = getNetwork($cf_subnet);
1441 | if ( ( $di >= $a ) && ( $di <= $b ) ) { $cloudflareIP = 1; }
1442 | }
1443 |
1444 | sub getIp {
1445 | return ( $_[0] * 256 * 256 * 256 ) +
1446 | ( $_[1] * 256 * 256 ) +
1447 | ( $_[2] * 256 ) +
1448 | $_[3];
1449 | }
1450 |
1451 | sub getNetwork {
1452 | @a = split( /[\/|\.]/, +shift );
1453 | return ( getIp( @a[ 0 .. 3 ] ),
1454 | ( getIp( @a[ 0 .. 3 ] ) + ( 2**( 32 - $a[4] ) ) ) );
1455 | }
1456 | return $cloudflareIP;
1457 | }
1458 |
1459 | sub check_for_nat {
1460 | return if ( !( -e ("/var/cpanel/cpnat") ) );
1461 | my $chkIP = $_[0];
1462 | open( CPNAT, "/var/cpanel/cpnat" );
1463 | my @CPNAT = ;
1464 | close(CPNAT);
1465 | my $cpnat;
1466 | foreach $cpnat (@CPNAT) {
1467 | chomp($cpnat);
1468 | my ( $outsideIP, $insideIP ) = ( split( /\s+/, $cpnat ) );
1469 | chomp($outsideIP);
1470 | chomp($insideIP);
1471 | if ( $outsideIP eq $chkIP ) {
1472 | return $insideIP;
1473 | }
1474 | if ( $insideIP eq $chkIP ) {
1475 | return $outsideIP;
1476 | }
1477 | }
1478 | }
1479 |
1480 | sub check_resolved_ip {
1481 | my $IP2CHK = $_[0];
1482 | my $RetVal = "";
1483 | if ( $IP2CHK eq $IPADDR ) {
1484 | $RetVal = GREEN . " [SAME]";
1485 | }
1486 | else {
1487 | $defaultsite = 1;
1488 | }
1489 | my $Is_IP_OnServer = qx[ ip addr | grep '$IP2CHK' ];
1490 | if ( !($Is_IP_OnServer) ) {
1491 | $RetVal = $RetVal .= RED . " [Not on this server]";
1492 | $defaultsite = 1;
1493 | }
1494 | my $IS_CLOUDFLARE = check_cloudflare_ips($IP2CHK);
1495 | if ($IS_CLOUDFLARE) {
1496 | $RetVal = " <-- CloudFlare DNS";
1497 | $defaultsite = 1;
1498 | }
1499 | my $IS_NAT = &check_for_nat($IP2CHK);
1500 | if ($IS_NAT) {
1501 | $RetVal = " NAT detected ($IS_NAT => $IP2CHK)";
1502 | if ( $IS_NAT eq $IPADDR ) {
1503 | $RetVal = $RetVal .= GREEN . " [SAME]";
1504 | $defaultsite = 0;
1505 | }
1506 | }
1507 | my $Is_IP_OnServer = qx[ ip addr | grep '$IS_NAT' ];
1508 | if ( !($Is_IP_OnServer) ) {
1509 | $RetVal = $RetVal .= RED . " [Not on this server]";
1510 | $defaultsite = 1;
1511 | }
1512 | return $RetVal;
1513 | }
1514 |
1515 | sub cruft_check {
1516 | &border;
1517 | print CYAN "CRUFT CHECK\n";
1518 | &border;
1519 | my $maxwidth = 25;
1520 | my $file2search = "";
1521 | my $TheStatus = "";
1522 | my $spacer = 0;
1523 | my $len = 0;
1524 | my $filestatus = "";
1525 | my $TrueUserLine = "";
1526 | my $isTerminated = 0;
1527 | my $termdate = "";
1528 | my @temp = undef;
1529 | my $DNSLineCnt = 0;
1530 | my $TotalDomainCnt = 0;
1531 |
1532 | # Check /var/cpanel/accounting.log file here (for CREATE and/or REMOVE lines)
1533 | # ONLY MAIN ACCT / DOMAIN is checked
1534 | print BLUE "From your query of "
1535 | . GREEN $QUERY
1536 | . BLUE " I have determined:\n";
1537 | my $isActive;
1538 | my $is_acct;
1539 | my $check_for;
1540 | open( ACCOUNTING, "/var/cpanel/accounting.log" );
1541 | foreach () {
1542 | @temp = split(/:/);
1543 | if ($IS_USERNAME) {
1544 | $check_for = ':' . $QUERY . '$';
1545 | }
1546 | else {
1547 | $check_for = ':' . $QUERY . ':';
1548 | }
1549 | if (/$check_for/) {
1550 | $is_acct = 1;
1551 | if (/CREATE/) {
1552 | $isActive = 1;
1553 | $isTerminated = 0;
1554 | chomp( $username = $temp[-1] );
1555 | chomp( $MAINDOMAIN = $temp[-3] );
1556 | }
1557 | if (/REMOVE/) {
1558 | chomp( $username = $temp[-1] );
1559 | chomp( $MAINDOMAIN = $temp[-2] );
1560 | $isActive = 0;
1561 | $isTerminated = 1;
1562 | @temp = ();
1563 | @temp = split(/:/);
1564 | $termdate = @temp[0] . ":" . @temp[1] . ":" . @temp[2];
1565 | }
1566 | }
1567 | }
1568 | close(ACCOUNTING);
1569 | if ($isTerminated) { ## $is_acct is true if this is the main account/domain
1570 | print "$MAINDOMAIN ($username) was terminated on $termdate\n";
1571 | }
1572 | if ($isActive) {
1573 | print
1574 | "$MAINDOMAIN ($username) is active (according to /var/cpanel/accounting.log)\n";
1575 | if ( $addoncnt > 0 ) {
1576 | print "It has $addoncnt Addon domains\n";
1577 | }
1578 | if ( $subcnt > 0 ) {
1579 | print "It has $addoncnt Sub domains\n";
1580 | }
1581 | if ( $parkcnt > 0 ) {
1582 | print "It has $addoncnt Aliased domains\n";
1583 | }
1584 |
1585 | # Add up the total number of additional domains
1586 | $TotalDomainCnt = $addoncnt + $subcnt + $parkcnt;
1587 |
1588 | # Now add one more to that for the main account
1589 | $TotalDomainCnt++;
1590 |
1591 | # Now count the number of "DNS" lines in /var/cpanel/users/$username and make sure
1592 | # it equalts $TotalDomainCnt. Warn if it does NOT!
1593 | $DNSLineCnt = qx[ grep -c '^DNS' /var/cpanel/users/$username ];
1594 | }
1595 |
1596 | # END OF ACCOUNTING LOG CHECK
1597 |
1598 | my $useQuery = 0;
1599 | if ( !$isActive
1600 | and !$is_acct
1601 | and !$isTerminated
1602 | and !$MAINDOMAIN
1603 | and !$username )
1604 | {
1605 | print
1606 | "No data found for your query of: $QUERY in /var/cpanel/accounting.log\n";
1607 | print "Continuing search for $QUERY...\n";
1608 |
1609 | # $username = $QUERY;
1610 | # $MAINDOMAIN = $QUERY;
1611 | }
1612 | if ( !$isActive ) {
1613 | my $isAddon;
1614 | my $isSub;
1615 | my $isParked;
1616 | $isAddon =
1617 | qx[ grep '^$QUERY:' /etc/userdatadomains | grep '==addon==' ];
1618 | if ($isAddon) {
1619 | ($username) = ( split( /\s+/, $isAddon ) )[1];
1620 | ($username) = ( split( /==/, $username ) );
1621 | ($isAddon) = ( split( /:/, $isAddon ) );
1622 | print
1623 | "$QUERY has an entry in /etc/userdatadomains as an Addon Domain under the "
1624 | . CYAN $username
1625 | . " user\n";
1626 | }
1627 | $isSub = qx[ grep '^$QUERY:' /etc/userdatadomains | grep '==sub==' ];
1628 | if ($isSub) {
1629 | ($username) = ( split( /\s+/, $isSub ) )[1];
1630 | ($username) = ( split( /==/, $username ) );
1631 | ($isSub) = ( split( /:/, $isSub ) );
1632 | print
1633 | "$QUERY has an entry in /etc/userdatadomains as a Sub Domain under the "
1634 | . CYAN $username
1635 | . " user\n"
1636 | unless ($isAddon);
1637 | }
1638 | $isParked =
1639 | qx[ grep '^$QUERY:' /etc/userdatadomains | grep '==parked==' ];
1640 | if ($isParked) {
1641 | ($username) = ( split( /\s+/, $isParked ) )[1];
1642 | ($username) = ( split( /==/, $username ) );
1643 | ($isParked) = ( split( /:/, $isParked ) );
1644 | print
1645 | "$QUERY has an entry in /etc/userdatadomains as a Aliased Domain under the "
1646 | . CYAN $username
1647 | . " user\n";
1648 | }
1649 | if ( !$MAINDOMAIN and $username ) {
1650 | ($MAINDOMAIN) =
1651 | ( split( /:/, qx[ grep '$username' /etc/trueuserdomains ] ) )[0];
1652 | chomp($MAINDOMAIN);
1653 | }
1654 | $useQuery = ($IS_USERNAME) ? 1 : 0;
1655 | if ( $useQuery and ( $isAddon or $isSub or $isParked ) ) {
1656 | print "Checking main domain $MAINDOMAIN ($username) instead...\n";
1657 | $QUERY = $username;
1658 | }
1659 | }
1660 | &smborder;
1661 |
1662 | my @FILES2SEARCH = qw(
1663 | /etc/passwd
1664 | /etc/group
1665 | /etc/shadow
1666 | /etc/gshadow
1667 | /etc/quota.conf
1668 | /etc/dbowners
1669 | /etc/userdomains
1670 | /etc/trueuserdomains
1671 | /etc/userdatadomains
1672 | /etc/userdatadomains.json
1673 | /etc/domainusers
1674 | /etc/trueuserowners
1675 | /etc/localdomains
1676 | /etc/remotedomains
1677 | /etc/demousers
1678 | /etc/email_send_limits
1679 | /etc/demoids
1680 | /etc/demodomains
1681 | /etc/ssldomains
1682 | /etc/apache2/conf/httpd.conf
1683 | /usr/local/apache/conf/httpd.conf
1684 | /var/cpanel/databases/users.db
1685 | );
1686 |
1687 | foreach $file2search (@FILES2SEARCH) {
1688 | chomp($file2search);
1689 | if ( !( -s ($file2search) ) ) {
1690 | my $filestat = $file2search . " is either empty or missing";
1691 | my $fileskip = CYAN "[SKIPPING]";
1692 | &print_output( $filestat, $fileskip );
1693 | next;
1694 | }
1695 | if ( $username eq "" ) {
1696 | $username = $QUERY;
1697 | }
1698 | if ( $MAINDOMAIN eq "" ) {
1699 | $MAINDOMAIN = $QUERY;
1700 | }
1701 | if ($useQuery) {
1702 | $filestatus = &check_file_existance( $file2search, $QUERY );
1703 | }
1704 | else {
1705 | $filestatus = &check_file_existance( $file2search, $username );
1706 | }
1707 | if ( !($filestatus) and !$useQuery ) {
1708 | $filestatus = &check_file_existance( $file2search, $MAINDOMAIN );
1709 | }
1710 | if ($filestatus) { $filestatus = GREEN "[EXISTS]"; }
1711 | else { $filestatus = RED "[MISSING]"; }
1712 | &print_output( $file2search, $filestatus );
1713 | }
1714 | if ($username) {
1715 |
1716 | # Check for home directory and others to see if they exist
1717 | my $hmCnt;
1718 | my $dirstatus = &check_dir("/$HOMEDIR/$username");
1719 | if ($dirstatus) { $dirstatus = GREEN "[EXISTS]"; }
1720 | else { $dirstatus = RED "[MISSING]"; }
1721 | &print_output( "$HOMEDIR/$username", $dirstatus );
1722 | if ( $dirstatus =~ m/MISSING/ ) {
1723 | if ($HOMEMATCH) {
1724 | print "Checking other possible home directory locations...\n";
1725 |
1726 | # Now check HOMEMATCH 1 through 9.
1727 | for ( $hmCnt = 1 ; $hmCnt < 10 ; $hmCnt = $hmCnt + 1 ) {
1728 | my $dirstatus = &check_dir("/$HOMEMATCH$hmCnt/$username");
1729 | if ($dirstatus) { $dirstatus = GREEN "[EXISTS]"; }
1730 | else { $dirstatus = RED "[MISSING]"; }
1731 | &print_output( "/$HOMEMATCH$hmCnt/$username", $dirstatus );
1732 | }
1733 | }
1734 | }
1735 |
1736 | # Check /var/cpanel/userdata/$username
1737 | my $dirstatus = &check_dir("/var/cpanel/userdata/$username");
1738 | if ($dirstatus) { $dirstatus = GREEN "[EXISTS]"; }
1739 | else { $dirstatus = RED "[MISSING]"; }
1740 | &print_output( "/var/cpanel/userdata/$username", $dirstatus );
1741 |
1742 | # Check main file in /var/cpanel/userdata/$username directory
1743 | my $dirstatus = &check_dir("/var/cpanel/userdata/$username/main");
1744 | if ($dirstatus) { $dirstatus = GREEN "[EXISTS]"; }
1745 | else { $dirstatus = RED "[MISSING]"; }
1746 | &print_output( "/var/cpanel/userdata/$username/main", $dirstatus );
1747 |
1748 | # Check /var/cpanel/users/$username
1749 | my $dirstatus = &check_dir("/var/cpanel/users/$username");
1750 | if ($dirstatus) { $dirstatus = GREEN "[EXISTS]"; }
1751 | else { $dirstatus = RED "[MISSING]"; }
1752 | &print_output( "/var/cpanel/users/$username", $dirstatus );
1753 | if ( $DNSLineCnt != $TotalDomainCnt ) {
1754 | print RED
1755 | "\t \\_ [WARN]: One or more DNS lines may be missing from this file!\n";
1756 | }
1757 |
1758 | # Check if /var/cpanel/databases/grants_$username.yaml exists!
1759 | my $dirstatus =
1760 | &check_dir("/var/cpanel/databases/grants_$username.yaml");
1761 | if ($dirstatus) { $dirstatus = GREEN "[EXISTS]"; }
1762 | else { $dirstatus = RED "[MISSING]"; }
1763 | &print_output( "/var/cpanel/databases/grants_$username.yaml",
1764 | $dirstatus );
1765 |
1766 | my $yaml_json = ( $CPVersion lt "11.50.0.0" ) ? "yaml" : "json";
1767 | my $dirstatus =
1768 | &check_dir("/var/cpanel/databases/$username.$yaml_json");
1769 | if ($dirstatus) { $dirstatus = GREEN "[EXISTS]"; }
1770 | else { $dirstatus = RED "[MISSING]"; }
1771 | &print_output( "/var/cpanel/databases/$username.$yaml_json",
1772 | $dirstatus );
1773 | my $dbindex =
1774 | ( $CPVersion lt "11.50.0.0" )
1775 | ? "/var/cpanel/databases/dbindex.db"
1776 | : "/var/cpanel/databases/dbindex.db.json";
1777 | my $dirstatus = &check_file_existance( $dbindex, $username );
1778 | if ($dirstatus) { $dirstatus = GREEN "[EXISTS]"; }
1779 | else { $dirstatus = RED "[MISSING]"; }
1780 | &print_output( $dbindex, $dirstatus );
1781 | my $dirstatus = &check_dir("/etc/proftpd/$username");
1782 | if ($dirstatus) { $dirstatus = GREEN "[EXISTS]"; }
1783 | else { $dirstatus = RED "[MISSING]"; }
1784 | &print_output( "/etc/proftpd/$username", $dirstatus );
1785 |
1786 | # Check for /var/cpanel/bandwidth/username.sqlite file.
1787 | my $dirstatus = &check_dir("/var/cpanel/bandwidth/$username.sqlite");
1788 | if ($dirstatus) { $dirstatus = GREEN "[EXISTS]"; }
1789 | else { $dirstatus = RED "[MISSING]"; }
1790 | &print_output( "/var/cpanel/bandwidth/$username.sqlite", $dirstatus );
1791 |
1792 | }
1793 | else {
1794 | print "Could not determine username so skipping all username checks!\n";
1795 | }
1796 | if ( !$IS_USERNAME ) {
1797 |
1798 | # Check /etc/valiases/$QUERY
1799 | my $dirstatus = &check_dir("/etc/valiases/$QUERY");
1800 | if ($dirstatus) { $dirstatus = GREEN "[EXISTS]"; }
1801 | else { $dirstatus = RED "[MISSING]"; }
1802 | &print_output( "/etc/valiases/$QUERY", $dirstatus );
1803 |
1804 | # Check /etc/vfilters/$QUERY
1805 | my $dirstatus = &check_dir("/etc/vfilters/$QUERY");
1806 | if ($dirstatus) { $dirstatus = GREEN "[EXISTS]"; }
1807 | else { $dirstatus = RED "[MISSING]"; }
1808 | &print_output( "/etc/vfilters/$QUERY", $dirstatus );
1809 |
1810 | # Check /var/named/$QUERY.db file
1811 | my $dirstatus = &check_dir("/var/named/$QUERY.db");
1812 | if ($dirstatus) { $dirstatus = GREEN "[EXISTS]"; }
1813 | else { $dirstatus = RED "[MISSING]"; }
1814 | &print_output( "/var/named/$QUERY.db", $dirstatus );
1815 |
1816 | # Check /etc/named.conf file
1817 | my $dirstatus = &check_file_existance( "/etc/named.conf", $QUERY );
1818 | if ($dirstatus) { $dirstatus = GREEN "[EXISTS]"; }
1819 | else { $dirstatus = RED "[MISSING]"; }
1820 | &print_output( "/etc/named.conf", $dirstatus );
1821 | }
1822 | else {
1823 | my $dirstatus = &check_dir("/etc/valiases/$MAINDOMAIN");
1824 | if ($dirstatus) { $dirstatus = GREEN "[EXISTS]"; }
1825 | else { $dirstatus = RED "[MISSING]"; }
1826 | &print_output( "/etc/valiases/$MAINDOMAIN", $dirstatus );
1827 |
1828 | # Check /etc/vfilters/$MAINDOMAIN
1829 | my $dirstatus = &check_dir("/etc/vfilters/$MAINDOMAIN");
1830 | if ($dirstatus) { $dirstatus = GREEN "[EXISTS]"; }
1831 | else { $dirstatus = RED "[MISSING]"; }
1832 | &print_output( "/etc/vfilters/$MAINDOMAIN", $dirstatus );
1833 |
1834 | # Check /var/named/$MAINDOMAIN.db file
1835 | my $dirstatus = &check_dir("/var/named/$MAINDOMAIN.db");
1836 | if ($dirstatus) { $dirstatus = GREEN "[EXISTS]"; }
1837 | else { $dirstatus = RED "[MISSING]"; }
1838 | &print_output( "/var/named/$MAINDOMAIN.db", $dirstatus );
1839 |
1840 | # Check /etc/named.conf file
1841 | my $dirstatus = &check_file_existance( "/etc/named.conf", $MAINDOMAIN );
1842 | if ($dirstatus) { $dirstatus = GREEN "[EXISTS]"; }
1843 | else { $dirstatus = RED "[MISSING]"; }
1844 | &print_output( "/etc/named.conf", $dirstatus );
1845 |
1846 | # Check for php-fpm conf files
1847 | my $dirstatus =
1848 | &check_dir("/opt/cpanel/ea-php*/root/etc/php-fpm.d/$MAINDOMAIN.conf");
1849 | if ($dirstatus) { $dirstatus = GREEN "[EXISTS]"; }
1850 | else { $dirstatus = RED "[MISSING]"; }
1851 | &print_output(
1852 | "/opt/cpanel/ea-php*/root/etc/php-fpm.d/$MAINDOMAIN.conf",
1853 | $dirstatus );
1854 | }
1855 |
1856 | # Check for DNS Clustering
1857 | if ( -e "/var/cpanel/useclusteringdns" ) {
1858 | print "Found DNS Cluster - checking...\n";
1859 | opendir( CLUSTERS, "/var/cpanel/cluster/root/config" );
1860 | my @DNSCLUSTERS = readdir(CLUSTERS);
1861 | closedir(CLUSTERS);
1862 | my ( $dnscluster, $QueryCluster );
1863 | foreach $dnscluster (@DNSCLUSTERS) {
1864 | chomp($dnscluster);
1865 | if ( $dnscluster eq "."
1866 | or $dnscluster eq ".."
1867 | or $dnscluster =~ m/dnsrole/
1868 | or $dnscluster =~ m/.cache/ )
1869 | {
1870 | next;
1871 | }
1872 | if ($IS_USERNAME) {
1873 | $QueryCluster = qx[ dig \@$dnscluster $MAINDOMAIN +short ];
1874 | if ($QueryCluster) {
1875 | print YELLOW "\t \\_ $MAINDOMAIN "
1876 | . GREEN ON_BLACK
1877 | . "was found in "
1878 | . YELLOW $dnscluster . "\n";
1879 | }
1880 | else {
1881 | print YELLOW "\t \\_ $MAINDOMAIN "
1882 | . RED
1883 | . "NOT found in "
1884 | . YELLOW $dnscluster . "\n";
1885 | }
1886 | }
1887 | else {
1888 | $QueryCluster = qx[ dig \@$dnscluster $QUERY +short ];
1889 | if ($QueryCluster) {
1890 | print YELLOW "\t \\_ $QUERY "
1891 | . GREEN ON_BLACK
1892 | . "was found in "
1893 | . $dnscluster . "\n";
1894 | }
1895 | else {
1896 | print YELLOW "\t \\_ $QUERY "
1897 | . RED
1898 | . "NOT found in "
1899 | . YELLOW $dnscluster . "\n";
1900 | }
1901 | }
1902 | }
1903 | }
1904 |
1905 | # Check MySQL users table.
1906 | my @MySQLUsers = undef;
1907 | my @MySQLDBs = undef;
1908 | my $MySQLUser;
1909 | my $MySQLDB;
1910 | my $first8;
1911 | if ($DBPrefix) {
1912 | if ( length($username) > 8 ) {
1913 | $first8 = substr( $username, 0, 8 );
1914 | }
1915 | else {
1916 | $first8 = $username;
1917 | }
1918 | }
1919 | else {
1920 | $first8 = $username;
1921 | }
1922 |
1923 | # Check for MySQL databases
1924 | my @MySQLDBs = qx[ mysql -BNe "show databases like '$first8%'" ];
1925 | my @MySQLDBsUnique = uniq(@MySQLDBs);
1926 | my $dbnum = @MySQLDBsUnique;
1927 | if ( $dbnum > 0 ) {
1928 | print YELLOW "MySQL Databases Found\n";
1929 | foreach $MySQLDB (@MySQLDBsUnique) {
1930 | chomp($MySQLDB);
1931 | print WHITE "\t \\_ " . $MySQLDB . "\n";
1932 | }
1933 | }
1934 |
1935 | # Check for database users
1936 | if ( $first8 eq "" ) {
1937 | print "Skipping MySQL User check - no username found!\n";
1938 | }
1939 | else {
1940 | my @MySQLUsers =
1941 | qx[ echo "SELECT User from mysql.user WHERE User REGEXP '$first8'" | mysql -BN ];
1942 | my @MySQLUsersUnique = uniq(@MySQLUsers);
1943 | my $num = @MySQLUsersUnique;
1944 | if ( $num > 0 ) {
1945 | print YELLOW "MySQL Users Found in MySQL.user table\n";
1946 | foreach $MySQLUser (@MySQLUsersUnique) {
1947 | chomp($MySQLUser);
1948 | print WHITE "\t \\_ " . $MySQLUser . "\n";
1949 | }
1950 | }
1951 | }
1952 |
1953 | # Check for postgres
1954 | my $psql_running = 0;
1955 | if (qx[ ps ax | grep postgres | grep -v grep ]) { $psql_running = 1; }
1956 | if ( -e ("/usr/bin/psql") and $psql_running )
1957 | { ## PostGreSQL is installed and running
1958 | my @check_postgres_users =
1959 | qx[ /usr/bin/psql -t -h localhost --username=postgres -c 'select usename from pg_user'|grep "$username" ];
1960 | if (@check_postgres_users) {
1961 | print YELLOW "PostGreSQL Users Found in pg_user database\n";
1962 | my @postgres_users = split( "\n", "@check_postgres_users" );
1963 | foreach (@postgres_users) {
1964 | chomp($_);
1965 | print WHITE "\t \\_" . $_ . "\n";
1966 | }
1967 | }
1968 | }
1969 | else {
1970 | print "\nPostGreSQL server is not installed (or running) on "
1971 | . MAGENTA $HOSTNAME . "\n";
1972 | }
1973 | &border;
1974 | print "\n" unless ($nocodeblock);
1975 | exit;
1976 | }
1977 |
1978 | sub check_file_existance {
1979 | my $TheFile = $_[0];
1980 | my $TheSearchString = $_[1];
1981 | my @TheFileData = undef;
1982 | my $DataLine = "";
1983 |
1984 | #my $FoundLine = 0;
1985 | my $FoundLine = "";
1986 | if ( -e ($TheFile) ) {
1987 |
1988 | # File exists, open it and read into array
1989 | # open( TheFile, "$TheFile" );
1990 | # @TheFileData = ;
1991 | # close(TheFile);
1992 | # foreach $DataLine (@TheFileData) {
1993 | # chomp($DataLine);
1994 |
1995 | #if ( $DataLine =~ m/\b$TheSearchString\b/ ) {
1996 | # if ( $DataLine =~ m/^$TheSearchString/ ) {
1997 | # $FoundLine = 1;
1998 | # last;
1999 | # }
2000 | # }
2001 | $FoundLine = qx[ grep -w '$TheSearchString' $TheFile ];
2002 | if ($FoundLine) { return 1; }
2003 | else { return 0; }
2004 | }
2005 | }
2006 |
2007 | sub print_output {
2008 | my $DisplayName = $_[0];
2009 | my $TheStatus = $_[1];
2010 | my $maxwidth = 30;
2011 | my $spacer = 0;
2012 | my $len = length($DisplayName);
2013 | $spacer = ( $maxwidth - $len ) + 50;
2014 | print YELLOW "$DisplayName";
2015 | printf "%" . $spacer . "s", $TheStatus;
2016 | print "\n";
2017 | select( undef, undef, undef, 0.25 );
2018 | }
2019 |
2020 | sub check_dir() {
2021 | my $Dir2Check = $_[0];
2022 | if ( -e ($Dir2Check) ) {
2023 | return 1;
2024 | }
2025 | else {
2026 | return 0;
2027 | }
2028 | }
2029 |
2030 | sub uniq {
2031 | my %seen;
2032 | grep !$seen{$_}++, @_;
2033 | }
2034 |
2035 | # Taken from ssp - Thanks to Chris Dillon!
2036 | sub version_cmp { # should only be used by version_compare()
2037 | no warnings 'uninitialized'
2038 | ; # Prevent uninitialized value warnings when not using all 4 values
2039 | my ( $a1, $b1, $c1, $d1 ) = split /[\._]/, $_[0];
2040 | my ( $a2, $b2, $c2, $d2 ) = split /[\._]/, $_[1];
2041 | return $a1 <=> $a2 || $b1 <=> $b2 || $c1 <=> $c2 || $d1 <=> $d2;
2042 | }
2043 |
2044 | sub version_compare {
2045 |
2046 | # example: return if version_compare($ver_string, qw( >= 1.2.3.3 ));
2047 | # Must be no more than four version numbers separated by periods and/or underscores.
2048 | my ( $ver1, $mode, $ver2 ) = @_;
2049 | return if ( $ver1 =~ /[^\._0-9]/ );
2050 | return if ( $ver2 =~ /[^\._0-9]/ );
2051 |
2052 | # Shamelessly copied the comparison logic out of Cpanel::Version::Compare
2053 | my %modes = (
2054 | '>' => sub {
2055 | return if $_[0] eq $_[1];
2056 | return version_cmp(@_) > 0;
2057 | },
2058 | '<' => sub {
2059 | return if $_[0] eq $_[1];
2060 | return version_cmp(@_) < 0;
2061 | },
2062 | '==' => sub { return $_[0] eq $_[1] || version_cmp(@_) == 0; },
2063 | '!=' => sub { return $_[0] ne $_[1] && version_cmp(@_) != 0; },
2064 | '>=' => sub {
2065 | return 1 if $_[0] eq $_[1];
2066 | return version_cmp(@_) >= 0;
2067 | },
2068 | '<=' => sub {
2069 | return 1 if $_[0] eq $_[1];
2070 | return version_cmp(@_) <= 0;
2071 | }
2072 | );
2073 | return if ( !exists $modes{$mode} );
2074 | return $modes{$mode}->( $ver1, $ver2 );
2075 | }
2076 |
2077 | # ripped from /usr/local/cpanel/Cpanel/Sys/OS.pm
2078 | sub get_release_version {
2079 | my $ises = 0;
2080 | my $ver;
2081 |
2082 | if ( open my $fh, '<', '/etc/redhat-release' ) {
2083 | my $line = readline $fh;
2084 | close $fh;
2085 | chomp $line;
2086 | if ( $line =~ m/(?:Corporate|Advanced\sServer|Enterprise)/i ) {
2087 | $ises = 1;
2088 | }
2089 | elsif ( $line =~ /CloudLinux|CentOS/i ) { $ises = 2; }
2090 | elsif ( $line =~ /WhiteBox/i ) { $ises = 3; }
2091 | elsif ( $line =~ /caos/i ) { $ises = 4; }
2092 | if ( $line =~ /(\d+\.\d+)/ ) { $ver = $1; }
2093 | elsif ( $line =~ /(\d+)/ ) { $ver = $1; }
2094 | }
2095 |
2096 | if ($ises) {
2097 | return ( $ver, $ises );
2098 | }
2099 | else {
2100 | return ( $ver, 0 );
2101 | }
2102 | }
2103 |
2104 | sub check_for_cagefs() {
2105 | return unless ( -e ("/usr/sbin/cagefsctl") );
2106 | my $tcageFSStats = qx[ /usr/sbin/cagefsctl --user-status $username ];
2107 | chomp($tcageFSStats);
2108 | return $tcageFSStats;
2109 | }
2110 |
2111 | sub get_php_version() {
2112 | return unless ($isEA4);
2113 | my $phpUserVersion;
2114 | my $userdataline;
2115 | my @USERDATA;
2116 |
2117 | # NOTE: If $IS_USERNAME, then use $MAINDOMAIN, otherwise use $QUERY.
2118 | my $tcDomain = "";
2119 | if ( $IS_USERNAME or $QUERY eq $MAINDOMAIN ) {
2120 | $tcDomain = $MAINDOMAIN;
2121 | }
2122 | else {
2123 | ($tcDomain) = ( split( /\./, $QUERY ) )[0];
2124 | $tcDomain = $tcDomain . "." . $MAINDOMAIN;
2125 | }
2126 | open( USERDATA, "/var/cpanel/userdata/$username/$tcDomain" );
2127 | @USERDATA = ;
2128 | close(USERDATA);
2129 | foreach $userdataline (@USERDATA) {
2130 | if ( $userdataline =~ m/phpversion:/ ) {
2131 | ($phpUserVersion) = ( split( /: /, $userdataline ) )[1];
2132 | chomp($phpUserVersion);
2133 | }
2134 | }
2135 | return $phpUserVersion;
2136 | }
2137 |
2138 | sub get_system_php_version() {
2139 | return unless ($isEA4);
2140 | open( PHPCONF, "/etc/cpanel/ea4/php.conf" );
2141 | my @PHPCONF = ;
2142 | close(PHPCONF);
2143 | my $phpconfline;
2144 | my $phpDefault;
2145 | foreach $phpconfline (@PHPCONF) {
2146 | chomp($phpconfline);
2147 | if ( $phpconfline =~ m/default:/ ) {
2148 | ($phpDefault) = ( split( /: /, $phpconfline ) )[1];
2149 | }
2150 | }
2151 | return $phpDefault;
2152 | }
2153 |
2154 | sub alltrim() {
2155 | my $string2trim = $_[0];
2156 | $string2trim =~ s/^\s*(.*?)\s*$/$1/;
2157 | return $string2trim;
2158 | }
2159 |
2160 | sub isEA4 {
2161 | if ( -f "/etc/cpanel/ea4/is_ea4" ) {
2162 | return 1;
2163 | }
2164 | return undef;
2165 | }
2166 |
2167 | sub display_mail_info {
2168 | if ($IS_USERNAME) {
2169 | $DOMAIN = $MAINDOMAIN;
2170 | }
2171 |
2172 | # first let's get the email accounts.
2173 | my $emailacctline;
2174 | opendir( EMAILACCTS, "$RealHome/mail/$DOMAIN" );
2175 | my @EMAILACCTS = readdir(EMAILACCTS);
2176 | closedir(EMAILACCTS);
2177 | my @SORTED2 = sort(@EMAILACCTS);
2178 | @EMAILACCTS = @SORTED2;
2179 | &smborder;
2180 |
2181 | # Check for suspended from outgoing email
2182 | my $SMTPUserSusp = qx[ grep $username /etc/outgoing_mail_suspended_users ];
2183 | if ($SMTPUserSusp) {
2184 | print RED "[WARN] - $username is suspended from sending email\n";
2185 | }
2186 |
2187 | # Check for hold from outgoing email
2188 | my $SMTPUserHold = qx[ grep $username /etc/outgoing_mail_hold_users ];
2189 | if ($SMTPUserHold) {
2190 | print RED "[WARN] - $username is on hold from sending email\n";
2191 | }
2192 |
2193 | if ( -s ("/etc/vdomainaliases/$DOMAIN") ) {
2194 | print YELLOW "[INFO] - "
2195 | . $DOMAIN
2196 | . CYAN
2197 | " listed in the /etc/vdomainaliases directory. Existing accounts/autoresponders will NOT forward!\n";
2198 | }
2199 |
2200 | print "Email accounts for $DOMAIN: \n";
2201 |
2202 | foreach $emailacctline (@EMAILACCTS) {
2203 | chomp($emailacctline);
2204 | next
2205 | if ( $emailacctline =~
2206 | /^\.|^\.\.|new|cur|tmp|mailboxes|storage|maildirsize|maildirfolder|subscriptions|dovecot/
2207 | );
2208 | $emailacctline =~ s/\///g; ## Strip trailing /
2209 | print CYAN "\t \\_ " . $emailacctline . "\@" . $DOMAIN . " ";
2210 |
2211 | # If v58+, get quota via doveadm command.
2212 | if ( $CPVersion gt "11.58.0.0" ) {
2213 | my $quotaline =
2214 | qx[ doveadm -f tab quota get -u $emailacctline\@$DOMAIN | grep 'Mailbox' | grep -v 'MESSAGE' ];
2215 | if ( $quotaline =~ m/Error: User doesn't exist/ ) {
2216 | print "[Quota cannot be determined]\n";
2217 | }
2218 | else {
2219 | my ( $qused, $qlimit, $qpercent ) =
2220 | ( split( /\s+/, $quotaline ) )[ 2, 3, 4 ];
2221 | if ( $qused == 0 ) {
2222 | $qused = 0;
2223 | }
2224 | else {
2225 | $qused = ( $qused / 1024 );
2226 | }
2227 | if ( $qlimit eq "-" ) {
2228 | $qlimit = "Unlimited";
2229 | }
2230 | else {
2231 | $qlimit = ( $qlimit / 1024 );
2232 | }
2233 | print "[Quota Used "
2234 | . $qused
2235 | . " MB of "
2236 | . $qlimit . " MB ("
2237 | . $qpercent . "%)]\n";
2238 | }
2239 | }
2240 | else {
2241 | print "\n";
2242 | }
2243 |
2244 | # Check the passwd and shadow files to make sure an entry exists
2245 | my $upasswdline;
2246 | my $ushadowline;
2247 | my $upasswdOK = 0;
2248 | my $ushadowOK = 0;
2249 | if ( -e ("$RealHome/etc/$DOMAIN/passwd") ) {
2250 | open( UPASSWD, "$RealHome/etc/$DOMAIN/passwd" );
2251 | my @UPASSWD = ;
2252 | close(UPASSWD);
2253 | my $upasswdstring = "$emailacctline:x:";
2254 | foreach $upasswdline (@UPASSWD) {
2255 | chomp($upasswdline);
2256 | if ( $upasswdline =~ m/^$upasswdstring/ ) {
2257 | $upasswdOK = 1;
2258 | last;
2259 | }
2260 | }
2261 | }
2262 | else {
2263 | print RED
2264 | "[WARN] - $RealHome/etc/$DOMAIN/passwd file is missing!\n";
2265 | $upasswdOK = 0;
2266 | next;
2267 | }
2268 |
2269 | # Check for suspended from incoming email
2270 | if ( -e ("$RealHome/etc/.$emailacctline\@$DOMAIN.suspended_incoming") )
2271 | {
2272 | print RED "\t \t \\_ incoming email suspended\n";
2273 | }
2274 |
2275 | # Shadow file
2276 | if ( -e ("$RealHome/etc/$DOMAIN/shadow") ) {
2277 | open( USHADOW, "$RealHome/etc/$DOMAIN/shadow" );
2278 | my @USHADOW = ;
2279 | close(USHADOW);
2280 | my $shadowstring = "$emailacctline:!!";
2281 | foreach $ushadowline (@USHADOW) {
2282 | chomp($ushadowline);
2283 | if ( $ushadowline =~ m/^$emailacctline/ ) {
2284 | if ( $ushadowline =~ m/^$shadowstring/ ) {
2285 | print RED "\t \t \\_ email login suspended\n";
2286 | }
2287 | $ushadowOK = 1;
2288 | last;
2289 | }
2290 | }
2291 | }
2292 | else {
2293 | print RED
2294 | "[WARN] - $RealHome/etc/$DOMAIN/shadow file is missing!\n";
2295 | $ushadowOK = 0;
2296 | next;
2297 | }
2298 | if ( !($upasswdOK) ) {
2299 | print RED
2300 | "\t\t \\_ [WARN] - Missing passwd entry for $emailacctline\@$DOMAIN";
2301 | print "\n";
2302 | }
2303 | if ( !($ushadowOK) ) {
2304 | print RED
2305 | "\t\t \\_ [WARN] - Missing shadow entry for $emailacctline\@$DOMAIN";
2306 | print "\n";
2307 | }
2308 |
2309 | # Check for .boxtrapperenable touch file - enabled if it exists.
2310 | if ( -e ("$RealHome/etc/$DOMAIN/$emailacctline/.boxtrapperenable") ) {
2311 | print YELLOW "\t \t \\_ Spam Boxtrapper Enabled\n";
2312 | }
2313 |
2314 | # Check for mailbox_format.cpanel file. Display contents if it exists
2315 | if (
2316 | -e ("$RealHome/mail/$DOMAIN/$emailacctline/mailbox_format.cpanel") )
2317 | {
2318 | my $mbformat =
2319 | qx [ cat "$RealHome/mail/$DOMAIN/$emailacctline/mailbox_format.cpanel" ];
2320 | chomp($mbformat);
2321 | print YELLOW "\t \t \\_ Account is using the $mbformat format.\n";
2322 | }
2323 |
2324 | # If a filter file exists in /$RealHome/etc/$DOMAIN/$emailacctline directory,
2325 | # Count the number of filters and display that here.
2326 | # As \_ User Level Filters: nn
2327 | my $filtercnt = 0;
2328 | my $ufilter;
2329 | my @UFILTER;
2330 | my @ufiltname;
2331 |
2332 | if ( -e ("$RealHome/etc/$DOMAIN/$emailacctline/filter") ) {
2333 | open( FILTFILE, "$RealHome/etc/$DOMAIN/$emailacctline/filter" );
2334 | my @UFILTER = ;
2335 | close(FILTFILE);
2336 | foreach $ufilter (@UFILTER) {
2337 | if ( substr( $ufilter, 0, 2 ) =~ m/# /
2338 | or substr( $ufilter, 0, 2 ) =~ m/#$/ )
2339 | {
2340 | next;
2341 | }
2342 | if ( substr( $ufilter, 0, 1 ) eq "#" ) {
2343 | push( @ufiltname, substr( $ufilter, 1 ) );
2344 | $filtercnt++;
2345 | }
2346 | }
2347 | if ( $filtercnt > 0 ) {
2348 | print YELLOW "\t \t \\_ has "
2349 | . $filtercnt
2350 | . " user level filters\n";
2351 | my $listfilt;
2352 | foreach $listfilt (@ufiltname) {
2353 | chomp($listfilt);
2354 | print MAGENTA "\t\t\t \\_ Name: " . $listfilt . "\n";
2355 | }
2356 | }
2357 | }
2358 | }
2359 | &smborder;
2360 |
2361 | # Now let's get the MX record and make sure the A record for it points to this server.
2362 | print "Checking MX records for $DOMAIN...\n";
2363 | my @MXRecords = getMXrecord($DOMAIN);
2364 | my $myline;
2365 | my $skipMXchk = 0;
2366 | foreach $myline (@MXRecords) {
2367 | chomp($myline);
2368 | if ( $myline eq "NONE" ) {
2369 | $skipMXchk = 1;
2370 | last;
2371 | }
2372 | }
2373 | my $IsRemote = 0;
2374 | my $MXRecord;
2375 | my $Is_IP_OnServer;
2376 | if ( !$skipMXchk ) {
2377 | if (@MXRecords) {
2378 | foreach $MXRecord (@MXRecords) {
2379 | chomp($MXRecord);
2380 | my $ARecordForMX;
2381 | my @ARecordForMX = getArecords($MXRecord);
2382 | foreach $ARecordForMX (@ARecordForMX) {
2383 | chomp($ARecordForMX);
2384 | my $IS_NAT = &check_for_nat($ARecordForMX);
2385 | if ($IS_NAT) { ## NAT IP ADDRESS RETURNED!
2386 | $Is_IP_OnServer = qx[ ip addr | grep '$IS_NAT' ];
2387 | if ($Is_IP_OnServer) {
2388 | print YELLOW
2389 | "\t \\_ $MXRecord resolves to $ARecordForMX => $IS_NAT (Configured on this server)\n";
2390 |
2391 | # Check reverse
2392 | my $ReverseOfMX = getptr($MXRecord);
2393 | if ( $ReverseOfMX eq $MXRecord ) {
2394 | print GREEN
2395 | "\t\t \\_ [OK] - $ARecordForMX reverses back to the MX: $MXRecord\n";
2396 | }
2397 | elsif ( $ReverseOfMX eq $HOSTNAME ) {
2398 | print GREEN
2399 | "\t\t \\_ [OK] - $ARecordForMX reverses back to the hostname: $HOSTNAME\n";
2400 | }
2401 | elsif ( $ReverseOfMX eq "mail.$MXRecord" ) {
2402 | print GREEN
2403 | "\t\t \\_ [OK] - $ARecordForMX reverses back to: mail.$MXRecord\n";
2404 | }
2405 | else {
2406 | if ( $ReverseOfMX eq "" ) {
2407 | $ReverseOfMX = "[NXDOMAIN]";
2408 | }
2409 | print RED
2410 | "\t\t \\_ [WARN] - $ARecordForMX reverses back to: $ReverseOfMX\n";
2411 | }
2412 | }
2413 | else {
2414 | print YELLOW
2415 | "\t \\_ $MXRecord resolves to $ARecordForMX (NOT configured on this server)\n";
2416 | $IsRemote = 1;
2417 | }
2418 | }
2419 | else { ## NO NAT FOUND!
2420 | $Is_IP_OnServer = qx[ ip addr | grep '$ARecordForMX' ];
2421 | if ($Is_IP_OnServer) {
2422 | print YELLOW
2423 | "\t \\_ $MXRecord resolves to $ARecordForMX (Configured on this server)\n";
2424 |
2425 | # Check reverse
2426 | my $ReverseOfMX = getptr($MXRecord);
2427 | if ( $ReverseOfMX eq $MXRecord ) {
2428 | print GREEN
2429 | "\t\t \\_ [OK] - $ARecordForMX reverses back to the MX: $MXRecord\n";
2430 | }
2431 | elsif ( $ReverseOfMX eq $HOSTNAME ) {
2432 | print GREEN
2433 | "\t\t \\_ [OK] - $ARecordForMX reverses back to the hostname $HOSTNAME\n";
2434 | }
2435 | elsif ( $ReverseOfMX eq "mail.$MXRecord" ) {
2436 | print GREEN
2437 | "\t\t \\_ [OK] - $ARecordForMX reverses back to mail.$MXRecord\n";
2438 | }
2439 | else {
2440 | if ( $ReverseOfMX eq "" ) {
2441 | $ReverseOfMX = "[NXDOMAIN]";
2442 | }
2443 | print RED
2444 | "\t\t \\_ [WARN] - $ARecordForMX reverses back to $ReverseOfMX\n";
2445 | }
2446 | }
2447 | else {
2448 | print YELLOW
2449 | "\t \\_ $MXRecord resolves to $ARecordForMX (NOT configured on this server)\n";
2450 | $IsRemote = 1;
2451 | }
2452 | }
2453 | }
2454 | }
2455 | }
2456 | }
2457 | else {
2458 | print CYAN "\t \\_ None\n";
2459 | }
2460 |
2461 | # Depending on whether $IsRemote is true or false, we check if the domain is listed in
2462 | # /etc/localdomains or /etc/remotedomains
2463 | &smborder;
2464 | my $IsInRemoteDomains = qx[ egrep -w '^$DOMAIN' /etc/remotedomains ];
2465 | my $IsInLocalDomains = qx[ egrep -w '^$DOMAIN' /etc/localdomains ];
2466 | chomp($IsInRemoteDomains);
2467 | chomp($IsInLocalDomains);
2468 | print "Checking email routing (based on MX check above)...\n";
2469 | if ($IsRemote) {
2470 |
2471 | if ($IsInRemoteDomains) {
2472 | print GREEN
2473 | "\t \\_ [OK] - $DOMAIN is listed in /etc/remotedomains\n";
2474 | $IsInLocalDomains = qx[ egrep -w '^$DOMAIN' /etc/localdomains ];
2475 | if ($IsInLocalDomains) {
2476 | print RED
2477 | "\t \\_ [WARN] - $DOMAIN was found in /etc/localdomains\n";
2478 | }
2479 | }
2480 | else {
2481 | print RED
2482 | "\t \\_ [WARN] - $DOMAIN is missing from /etc/remotedomains\n";
2483 | if ($IsInLocalDomains) {
2484 | print RED
2485 | "\t \\_ [WARN] - $DOMAIN was found in /etc/localdomains\n";
2486 | print YELLOW
2487 | "\t \\_ [NOTE] - OK if MX record is pointing to an external anti-spam service/gateway\n";
2488 | }
2489 | }
2490 | }
2491 | else { ## is local
2492 | if ($IsInLocalDomains) {
2493 | print GREEN
2494 | "\t \\_ [OK] - $DOMAIN is listed in /etc/localdomains\n";
2495 | $IsInRemoteDomains = qx[ egrep -w '^$DOMAIN' /etc/remotedomains ];
2496 | if ($IsInRemoteDomains) {
2497 | print RED
2498 | "\t \\_ [WARN] - $DOMAIN was found in /etc/remotedomains\n";
2499 | }
2500 | }
2501 | else {
2502 | print RED
2503 | "\t \\_ [WARN] - $DOMAIN is missing from /etc/localdomains\n";
2504 | if ($IsInRemoteDomains) {
2505 | print RED
2506 | "\t \\_ [WARN] - $DOMAIN was found in /etc/remotedomains\n";
2507 | }
2508 | }
2509 | }
2510 |
2511 | # Now list aliases (if any)
2512 | my $emailfwd;
2513 | my $fwdtype;
2514 | my $listfwd;
2515 | &smborder;
2516 | print "Aliases/Forwarders:\n";
2517 | open( FORWARDERS, "/etc/valiases/$DOMAIN" );
2518 | my @FWDS = ;
2519 | close(FORWARDERS);
2520 |
2521 | if (@FWDS) {
2522 | foreach $emailfwd (@FWDS) {
2523 | chomp($emailfwd);
2524 | if ( $emailfwd =~ m/: / ) { $fwdtype = "(normal forward/alias)"; }
2525 | if ( $emailfwd =~ m/\*:/ ) {
2526 | $fwdtype = "(deliver to $username main account)";
2527 | }
2528 | if ( $emailfwd =~ m/:fail:/ ) {
2529 | $fwdtype = "(fail - bounce with message)";
2530 | }
2531 | if ( $emailfwd =~ m/:blackhole:/ ) {
2532 | $fwdtype = "(blackhole - discard [not recommended])";
2533 | }
2534 | if ( $emailfwd =~ m/\|/ ) { $fwdtype = "(pipe to program)"; }
2535 | if ( $emailfwd =~ m/autorespond/ ) {
2536 | $fwdtype = "(auto responder)";
2537 | }
2538 | if ( $emailfwd =~ m/mailman\/mail/ ) {
2539 | $fwdtype = "(mailman list)";
2540 | ($listfwd) = ( split( /\s+/, $emailfwd ) )[0];
2541 | $emailfwd = $listfwd;
2542 | }
2543 | print YELLOW "\t \\_ " . $emailfwd . " " . $fwdtype . "\n";
2544 | }
2545 | }
2546 | else {
2547 | print CYAN "\t \\_ None\n";
2548 | }
2549 |
2550 | # get any system level filters (from /etc/vfilters/$DOMAIN file)
2551 | my $gfilter;
2552 | &smborder;
2553 | print "Global Level (system) Filters:\n";
2554 | open( GFILTFILE, "/etc/vfilters/$DOMAIN" );
2555 | my @GFILTER = ;
2556 | my $gfiltercnt = 0;
2557 | my @gfiltname;
2558 | close(GFILTFILE);
2559 |
2560 | if (@GFILTER) {
2561 | foreach $gfilter (@GFILTER) {
2562 | if ( substr( $gfilter, 0, 2 ) =~ m/# /
2563 | or substr( $gfilter, 0, 2 ) =~ m/#$/ )
2564 | {
2565 | next;
2566 | }
2567 | if ( substr( $gfilter, 0, 1 ) eq "#" ) {
2568 | push( @gfiltname, substr( $gfilter, 1 ) );
2569 | $gfiltercnt++;
2570 | }
2571 | }
2572 | print CYAN "\t \t \\_ "
2573 | . $DOMAIN . " has "
2574 | . $gfiltercnt
2575 | . " global level filters\n";
2576 | my $glistfilt;
2577 | foreach $glistfilt (@gfiltname) {
2578 | chomp($glistfilt);
2579 | print YELLOW "\t\t\t \\_ Name: " . $glistfilt . "\n";
2580 | }
2581 | }
2582 | else {
2583 | print CYAN "\t \\_ None\n";
2584 | }
2585 |
2586 | # Here we add the spf record and dkim record (if they exist).
2587 | my $spf = qx[ dig \@208.67.222.222 $DOMAIN TXT +short | grep 'spf1' ];
2588 | my $dkim = qx[ dig \@208.67.220.220 default._domainkey.$DOMAIN TXT +short ];
2589 | my $dmarc = qx[ dig \@208.67.222.222 _dmarc.$DOMAIN TXT +short ];
2590 | print "Checking SPF Record For $DOMAIN\n";
2591 | if ($spf) {
2592 | print YELLOW "\t \\_ " . $spf;
2593 | if ( $spf =~ m/\+all/ ) {
2594 | print CYAN
2595 | "\t\t \\_ Pass All (Allow all email! Like not having any SPF at all)\n";
2596 | }
2597 | if ( $spf =~ m/\-all/ ) {
2598 | print CYAN
2599 | "\t\t \\_ Hard Fail (Reject all email unless from ipv4/ipv6, mx or a)\n";
2600 | }
2601 | if ( $spf =~ m/\~all/ ) {
2602 | print CYAN
2603 | "\t\t \\_ Soft Fail (Allow mail from anywhere, but mark as possible forgery) [DEFAULT]\n";
2604 | }
2605 | if ( $spf =~ m/\?all/ ) {
2606 | print CYAN
2607 | "\t\t \\_ Neutral (No policy statement! Like not having any SPF at all)\n";
2608 | }
2609 | print "\n";
2610 | }
2611 | else {
2612 | print YELLOW "\t \\_ None\n";
2613 | }
2614 | print "Checking DKIM Record For default._domainkey.$DOMAIN\n";
2615 | if ($dkim) {
2616 | print YELLOW "\t \\_ " . $dkim . "\n";
2617 | }
2618 | else {
2619 | print YELLOW "\t \\_ None\n";
2620 | }
2621 | print "Checking DMARC Record For _dmarc.$DOMAIN\n";
2622 | if ($dmarc) {
2623 | print YELLOW "\t \\_ " . $dmarc . "\n";
2624 | }
2625 | else {
2626 | print YELLOW "\t \\_ None\n";
2627 | }
2628 |
2629 | # Add MAX_EMAIL_PER_HOUR, MAX_DEFER_FAIL_PERCENTAGE, MAILBOX_FORMAT
2630 | $MAILBOX_FORMAT = $user_conf->{'MAILBOX_FORMAT'};
2631 | $MAX_EMAIL_PER_HOUR = $user_conf->{'MAX_EMAIL_PER_HOUR'};
2632 | $MAX_DEFER_FAIL_PERCENTAGE = $user_conf->{'MAX_DEFER_FAIL_PERCENTAGE'};
2633 | $MAXPOP = $user_conf->{'MAXPOP'};
2634 | print WHITE "Max Mail Accounts " . CYAN $MAXPOP . "\n";
2635 | print WHITE "Mailbox Format: " . CYAN ucfirst($MAILBOX_FORMAT) . "\n";
2636 | print WHITE "Max Emails Per Hour: "
2637 | . CYAN ucfirst($MAX_EMAIL_PER_HOUR) . "\n";
2638 | print WHITE "Max Defer Fail %: "
2639 | . CYAN ucfirst($MAX_DEFER_FAIL_PERCENTAGE) . "\n";
2640 |
2641 | # Check here if send mail from dedicated IP is set and if /etc/mailips or /etc/mailhelo is
2642 | # referenced.
2643 | my $SendFromDedicated =
2644 | qx[ grep 'per_domain_mailips=1' /etc/exim.conf.localopts ];
2645 | $SendFromDedicated = ($SendFromDedicated) ? "Yes" : "No";
2646 | my $CustomHelo = qx[ grep 'custom_mailhelo=1' /etc/exim.conf.localopts ];
2647 | $CustomHelo = ($CustomHelo) ? "Yes" : "No";
2648 | my $CustomMailIP = qx[ grep 'custom_mailips=1' /etc/exim.conf.localopts ];
2649 | $CustomMailIP = ($CustomMailIP) ? "Yes" : "No";
2650 | my $CustomMailIPText = "";
2651 |
2652 | if ( $CustomMailIP eq "Yes" ) {
2653 | $CustomMailIPText = qx[ egrep '^$MAINDOMAIN' /etc/mailips ];
2654 | chomp($CustomMailIPText);
2655 | }
2656 | my $CustomHeloText = "";
2657 | if ( $CustomHelo eq "Yes" ) {
2658 | $CustomHeloText = qx[ egrep '^$MAINDOMAIN' /etc/mailhelo ];
2659 | chomp($CustomHeloText);
2660 | }
2661 | print WHITE "Send from dedicated IP: " . CYAN $SendFromDedicated . "\n";
2662 | print WHITE "Using Custom HELO (/etc/mailhelo): "
2663 | . CYAN $CustomHelo . " "
2664 | . YELLOW $CustomHeloText . "\n";
2665 | print WHITE "Using Custom IP (/etc/mailips): "
2666 | . CYAN $CustomMailIP . " "
2667 | . YELLOW $CustomMailIPText . "\n";
2668 | &border;
2669 | }
2670 |
2671 | sub getMXrecord {
2672 | my $tcDomain = $_[0];
2673 | my $rr;
2674 | my @NEWMX;
2675 | my $res = Net::DNS::Resolver->new;
2676 | my @mx = mx( $res, $tcDomain );
2677 | if (@mx) {
2678 | foreach $rr (@mx) {
2679 | push( @NEWMX, $rr->exchange );
2680 | }
2681 | return @NEWMX;
2682 | }
2683 | else {
2684 | return "NONE";
2685 | }
2686 | }
2687 |
2688 | sub getptr() {
2689 | my $ip = $_[0];
2690 | chomp($ip);
2691 | my $ipaddr = inet_aton($ip);
2692 | my $ptrname = gethostbyaddr( $ipaddr, AF_INET );
2693 | return $ptrname;
2694 | }
2695 |
2696 | sub getArecords {
2697 | my $tcDomain = $_[0];
2698 | my @addresses = gethostbyname($tcDomain);
2699 | @addresses = map { inet_ntoa($_) } @addresses[ 4 .. $#addresses ];
2700 | return @addresses;
2701 | }
2702 |
2703 | sub scan {
2704 | my $URL =
2705 | "https://raw.githubusercontent.com/cPanelPeter/infection_scanner/master/strings.txt";
2706 | my @DEFINITIONS = qx[ curl -s $URL ];
2707 | my $StringCnt = @DEFINITIONS;
2708 |
2709 | # Need to define and use $RealHome if $HOMEDIR doesn't exist!!!
2710 | open( PASSWD, "/etc/passwd" );
2711 | @PASSWDS = ;
2712 | close(PASSWD);
2713 | foreach $passline (@PASSWDS) {
2714 | chomp($passline);
2715 | if ( $passline =~ m/\b$username\b/ ) {
2716 | ($UID) = ( split( /:/, $passline ) )[2];
2717 | ($GID) = ( split( /:/, $passline ) )[3];
2718 | ($RealHome) = ( split( /:/, $passline ) )[5];
2719 | ($RealShell) = ( split( /:/, $passline ) )[6];
2720 | last;
2721 | }
2722 | }
2723 |
2724 | print "Scanning $RealHome for ($StringCnt) known infections:\n";
2725 | my @SEARCHSTRING = sort(@DEFINITIONS);
2726 | my @FOUND = undef;
2727 | my $SOMETHING_FOUND = 0;
2728 | my $SEARCHSTRING;
2729 | my ( $sec, $min, $hour, $mday, $mon, $year );
2730 | my $scanstarttime = Time::Piece->new;
2731 |
2732 | print "Scan started on $scanstarttime\n";
2733 |
2734 | foreach $SEARCHSTRING (@SEARCHSTRING) {
2735 | &spin;
2736 | chomp($SEARCHSTRING);
2737 | my $SCAN =
2738 | qx[ grep -srIl --exclude-dir=www --exclude-dir=mail --exclude-dir=tmp --exclude=*.png --exclude=*.svg --exclude-dir=access-logs -w "$SEARCHSTRING" $RealHome/* ];
2739 |
2740 | chomp($SCAN);
2741 | if ($SCAN) {
2742 | $SOMETHING_FOUND = 1;
2743 | $SEARCHSTRING =~ s/\\//g;
2744 | print YELLOW "\n\n\bThe phrase "
2745 | . CYAN
2746 | . $SEARCHSTRING
2747 | . YELLOW
2748 | . " was found in file(s)\n";
2749 | print GREEN
2750 | "==================================================================\n";
2751 | print RED "$SCAN\n";
2752 | }
2753 | }
2754 | if ( $SOMETHING_FOUND == 0 ) {
2755 | print GREEN "\bNothing suspicious found!\n";
2756 | }
2757 | print "\n";
2758 | my $scanendtime = Time::Piece->new;
2759 | print "Scan completed on $scanendtime\n";
2760 | my $scantimediff = ( $scanendtime - $scanstarttime );
2761 | print "Elapsed Time: ", $scantimediff->pretty, "\n";
2762 | print "\n" unless ($nocodeblock);
2763 | }
2764 |
2765 | sub spin {
2766 | my %spinner = ( '|' => '/', '/' => '-', '-' => '\\', '\\' => '|' );
2767 | $spincounter = ( !defined $spincounter ) ? '|' : $spinner{$spincounter};
2768 | print STDERR "\b$spincounter";
2769 | }
2770 |
2771 | sub getSSLprovider {
2772 | my $RetVal = "";
2773 | if ( !( -e ("/var/cpanel/autossl.json") ) ) {
2774 | $RetVal = "Disabled";
2775 | return $RetVal;
2776 | }
2777 | my $CurrentProvider =
2778 | qx[ grep '"provider":"cPanel"' /var/cpanel/autossl.json ];
2779 | if ($CurrentProvider) { $RetVal = "cPanel (Powered by Comodo)"; }
2780 | my $CurrentProvider =
2781 | qx[ grep '"provider":"LetsEncrypt"' /var/cpanel/autossl.json ];
2782 | if ($CurrentProvider) { $RetVal = "Let's Encrypt"; }
2783 | my $CurrentProvider = qx[ grep '"provider":null' /var/cpanel/autossl.json ];
2784 | if ($CurrentProvider) { $RetVal = "Disabled"; }
2785 | return $RetVal;
2786 | }
2787 |
2788 | sub ChkForIntegration {
2789 | return unless ( -e "/var/cpanel/integration/dynamicui/$username" );
2790 | print YELLOW "[NOTE] * Integration links found in " . GREEN
2791 | . "/var/cpanel/integration/dynamicui/$username\n";
2792 | }
2793 |
2794 | sub dispSSLdata {
2795 | my $tcDomain = $_[0];
2796 | my $CNloc = index( $sslsubject, "CN=" );
2797 | my $CN = substr( $sslsubject, $CNloc );
2798 | my ( $domain, $crap ) = ( split( /\//, $CN ) )[0];
2799 | $domain = substr( $domain, 3 );
2800 | chomp($domain);
2801 | chomp($startdate);
2802 | chomp($expiredate);
2803 | ($startdate) = ( split( /=/, $startdate ) )[1];
2804 | ($expiredate) = ( split( /=/, $expiredate ) )[1];
2805 | my $isExpired;
2806 |
2807 | if ( $noDateManip == 0 ) {
2808 | my $unix_time = UnixDate( ParseDate($expiredate), "%s" );
2809 | my $time_now = qx[ date -u ];
2810 | chomp($time_now);
2811 | my $unix_time_now = UnixDate( ParseDate($time_now), "%s" );
2812 | $isExpired = GREEN "[VALID]";
2813 | if ( $unix_time_now > $unix_time ) {
2814 | $isExpired = RED "[EXPIRED]";
2815 | }
2816 | }
2817 | print YELLOW . $domain . "\n";
2818 | print WHITE "\t \\_ Not Before: " . GREEN . $startdate . "\n";
2819 | print WHITE "\t \\_ Not After : "
2820 | . GREEN
2821 | . $expiredate . " "
2822 | . $isExpired . "\n";
2823 | if ($isSelfSigned) {
2824 | print RED "\t \\_ [WARN] " . WHITE "- Self-Signed Certificate\n";
2825 | }
2826 | else {
2827 | # Get Issuer and display it.
2828 | my $SSLIssuer =
2829 | qx[ openssl x509 -in "$sslsyscertdir/$tcDomain/certificates" -issuer -noout ];
2830 | my $Oloc = index( $SSLIssuer, "O=" );
2831 | my $O = substr( $SSLIssuer, $Oloc );
2832 | my ( $SSLIssuer, $crap ) = ( split( /\//, $O ) )[0];
2833 | $SSLIssuer = substr( $SSLIssuer, 2 );
2834 | chomp($SSLIssuer);
2835 | print GREEN "\t \\_ [CA SIGNED] " . WHITE "Issued by: $SSLIssuer\n";
2836 | }
2837 | }
2838 |
2839 | sub oldlistssls {
2840 | my $sslcertdir = "$RealHome/ssl/certs";
2841 | my $sslsyscertdir = "/var/cpanel/ssl/installed/certs";
2842 | my @certs;
2843 | my $cert;
2844 | my $sslsubject;
2845 | my $startdate;
2846 | my $expiredate;
2847 | if ( -e ("$sslcertdir") ) {
2848 | print WHITE "SSL Certificates installed under "
2849 | . CYAN $MAINDOMAIN
2850 | . WHITE " ("
2851 | . GREEN $username
2852 | . WHITE ")\n";
2853 | opendir( ssldir, "$sslcertdir" );
2854 | my @certs = readdir(ssldir);
2855 | closedir(ssldir);
2856 | foreach $cert (@certs) {
2857 | my $SSLNotInstalled = 0;
2858 | chomp($cert);
2859 | if ( $cert eq "."
2860 | or $cert eq ".."
2861 | or ( substr( $cert, -4 ) ne '.crt' ) )
2862 | {
2863 | next;
2864 | }
2865 | if ( !( -e ("$sslsyscertdir/$cert") ) ) {
2866 | next;
2867 | }
2868 | $sslsubject =
2869 | qx[ openssl x509 -in "$sslcertdir/$cert" -subject -noout ];
2870 | my $CNloc = index( $sslsubject, "CN=" );
2871 | my $CN = substr( $sslsubject, $CNloc );
2872 | my ( $domain, $crap ) = ( split( /\//, $CN ) )[0];
2873 | $domain = substr( $domain, 3 );
2874 | chomp($domain);
2875 | $startdate =
2876 | qx[ openssl x509 -in "$sslcertdir/$cert" -startdate -noout ];
2877 | $expiredate =
2878 | qx[ openssl x509 -in "$sslcertdir/$cert" -enddate -noout ];
2879 | chomp($startdate);
2880 | chomp($expiredate);
2881 | ($startdate) = ( split( /=/, $startdate ) )[1];
2882 | ($expiredate) = ( split( /=/, $expiredate ) )[1];
2883 | my $isExpired;
2884 |
2885 | if ( $noDateManip == 0 ) {
2886 | my $unix_time = UnixDate( ParseDate($expiredate), "%s" );
2887 | my $time_now = qx[ date -u ];
2888 | chomp($time_now);
2889 | my $unix_time_now = UnixDate( ParseDate($time_now), "%s" );
2890 | $isExpired = GREEN "[VALID]";
2891 | if ( $unix_time_now > $unix_time ) {
2892 | $isExpired = RED "[EXPIRED]";
2893 | }
2894 | }
2895 | print YELLOW . $domain . MAGENTA " (" . $cert . ")\n";
2896 | print WHITE "\t \\_ Not Before: " . GREEN . $startdate . "\n";
2897 | print WHITE "\t \\_ Not After : "
2898 | . GREEN
2899 | . $expiredate . " "
2900 | . $isExpired . "\n";
2901 |
2902 | # Check if self-signed
2903 | my $isSelfSigned =
2904 | qx[ openssl verify "$sslcertdir/$cert" | grep 'self signed certificate' ];
2905 | if ($isSelfSigned) {
2906 | print RED "\t \\_ [WARN] "
2907 | . WHITE "- Self-Signed Certificate\n";
2908 | }
2909 | else {
2910 | # Get Issuer and display it.
2911 | my $SSLIssuer =
2912 | qx[ openssl x509 -in "$sslcertdir/$cert" -issuer -noout ];
2913 | my $Oloc = index( $SSLIssuer, "O=" );
2914 | my $O = substr( $SSLIssuer, $Oloc );
2915 | my ( $SSLIssuer, $crap ) = ( split( /\//, $O ) )[0];
2916 | $SSLIssuer = substr( $SSLIssuer, 2 );
2917 | chomp($SSLIssuer);
2918 | print GREEN "\t \\_ [CA SIGNED] "
2919 | . WHITE "Issued by: $SSLIssuer\n";
2920 | }
2921 |
2922 | # List SAN's
2923 | print WHITE
2924 | "This certificate is protecting the following Subject Alternative Names:\n";
2925 | my $SAN;
2926 | my @getSANS =
2927 | qx[ openssl x509 -in "$sslcertdir/$cert" -noout -text | grep -oP '(?<=DNS:)[a-z0-9.-]+' ];
2928 | foreach $SAN (@getSANS) {
2929 | chomp($SAN);
2930 | print YELLOW "\t \\_ " . CYAN $SAN . "\n";
2931 | }
2932 | }
2933 | }
2934 | else {
2935 | print WHITE "No SSL Certificates found for "
2936 | . CYAN $MAINDOMAIN
2937 | . WHITE " ("
2938 | . GREEN $username
2939 | . WHITE ")\n";
2940 | }
2941 |
2942 | # Check for pending AutoSSL orders here (uses whmapi1 get_autossl_pending_queue (62.0.26+ only)
2943 | if ( $CPVersion gt "11.60.0.26" ) {
2944 | if ( $SSLProvider eq "cPanel (Powered by Comodo)" ) {
2945 | print "\nChecking for pending AutoSSL orders: \n";
2946 | my $SSL_PENDING =
2947 | qx[ whmapi1 get_autossl_pending_queue | grep -B3 'user: $username' ];
2948 | if ($SSL_PENDING) {
2949 | my $NEW_SSL_PENDING;
2950 | ( $NEW_SSL_PENDING = $SSL_PENDING ) =~
2951 | s/order_item_id: /order_item_id: https:\/\/manage2.cpanel.net\/certificate.cgi\?oii=/g;
2952 | $SSL_PENDING = $NEW_SSL_PENDING;
2953 | print GREEN "\t \\_ \n";
2954 | print GREEN "$SSL_PENDING";
2955 | }
2956 | else {
2957 | print GREEN "\t \\_ None";
2958 | }
2959 | print "\n";
2960 | }
2961 | }
2962 |
2963 | # Check for CAA records here.
2964 | print "Checking for CAA records: \n";
2965 | my @HasCAA = qx[ dig $MAINDOMAIN caa +short ];
2966 | my $CAARecord;
2967 | if (@HasCAA) {
2968 | print YELLOW "[NOTE] * CAA records were found for $MAINDOMAIN\n";
2969 | print GREEN
2970 | "SSL Certificates can only be issued from the following CA's:\n";
2971 | foreach $CAARecord (@HasCAA) {
2972 | chomp($CAARecord);
2973 | print CYAN "\t \\_ $CAARecord\n";
2974 | }
2975 | }
2976 | else {
2977 | print GREEN "\t \\_ None\n";
2978 | }
2979 | &border;
2980 | }
2981 |
2982 | sub isUserReserved {
2983 | my $lcUser = $_[0];
2984 | my $UserList;
2985 | my @UserList =
2986 | qx[ /usr/local/cpanel/3rdparty/bin/perl -MCpanel::Validate::Username -MData::Dumper -e 'print Dumper(Cpanel::Validate::Username::list_reserved_usernames());' ];
2987 | foreach $UserList (@UserList) {
2988 | chomp($UserList);
2989 | if ( $UserList =~ $lcUser ) {
2990 | return 1;
2991 | }
2992 | }
2993 | }
2994 |
--------------------------------------------------------------------------------