Root privilege scripts from Apache

If you have a script that needs to access functions that can only be run as root (e.g. chmod, chgrp, mkdir, etc) you will find that you can’t call these directly since the Apache user is not root (at least it should not be root). There is no perfect solution around this as all solutions involve some security risk, but the least bad seems to be to use sudoer to grant root privileges to the script and then lock down the script so nobody other than root can modify the script.

First chmod the script so that anyone can execute it, but nobody other than root can modify it (I am assuming here that you are logged in as root, otherwise sudo).

chmod 111 /home/path_to_script

Next modify sudoer using visudo. It is a good idea to use visudo so that any change you make are updated without having to restart sudo.

# visudo

Add the following line after the root entry in sudoer

apache_user ALL = NOPASSWD: /home/path_to_script

Change the apache_user to whatever your apache user is (e.g. nobody) and then add the path to your script. You might want to add your favorite editor (mine is nano) to your export in .bashrc. You should now be able to call your script from apache without problem.

Update. Make sure that you have commented out the Defaults requiretty line in visudo or else the script won’t be run by Apache. This problem wasted a couple of hours of my time since the script would run fine from the bash shell of the apache user, but not when called by apache. I finally took a look at the log file (yes I should have done this first) and there was the problem sudo: sorry, you must have a tty to run sudo!

Adding iso repository under XenServer 5.5

If you want to install an OS from a local repository under XenServer 5.5 then you need to do the following. The documentation on how to do this in the xenserver manual is incomplete.

first ssh into the xenserver
mkdir -p /var/opt/xen/iso_import
Copy your ISO images to the /var/opt/xen/iso_import directory using scp.
Create a repository with this command:
xe sr-create name-label=ISOs type=iso device-config:location=/var/opt/xen/iso_import device-config:legacy_mode=true content-type=iso
You then need to attach the ISO library with this command (nicely not mentioned in the citrix documentation)
xe-mount-iso-sr /var/opt/xen/iso_import

You should then be able to create a VM using the .iso

How to get total folder / directory size with Linux

If you want to know how much disk space is being used by a directory (including all the sub-directories) then you can use the following command. It will output a single number in human readable form (eg 8.2G). I have found this very useful for finding where all my disk space has gone.

du -h | grep -v '/' | awk '{print $1}'

X11 ssh-forwarding of a gnome-session to Mac OS X 10.5

If you want to X11 ssh-forward a gnome-session on a remote linux server to MacOS X Leopard there seems to be some bug in the 10.5 X11 that causes the gnome desktop to take over the whole screen and you can’t access the session. The solution is to open the gnome-session using Xnest instead. This opens the session in a small X11 window (1024×768 in the example below).

Xnest -geometry 1024x768 :1& DISPLAY=:1 ssh -X <HOST> gnome-session

How to compare the remote and local versions of a file in Dreamweaver

I was recently faced with working out what had changed in one of my big php files on the remote server (someone naughty had been playing with it). I use Mac OSX Dreamweaver and after a bit of searching around I found the following way to make Dreamweaver easily show you what has changed. This is not really anything major but it might save someone a bit of time.

First download and install TextWrangler. It is free and quite a nice text editing program.

Next open “Preferences” in Dreamweaver and select “File Compare”.

In “File Compare” browse to the “usr/bin/” folder and select “twdiff”.

Press OK and then go back to the main menu.

Open in Dreamweaver the local file in that you want to compare with the remote version. Select “Compare with Remote” from the “File” menu.

TextWrangler will now launch showing you the difference between the local version and the remote version. You can then chose to keep or reject any of the changes.

How to upgrade from php4 to php5 on CentOS 4

This is surprisingly difficult to find out how to do. You can’t just type “yum update php” as CentOS 4.4 only has php4 in its base repository. Php5 does exist in the centosplus repository but you need to configure yum to allow this to be used. The basic instructions for doing this are:

yum install yum-plugin-priorities

This installs the priority plugin which allows you to chose to only upgrade the packages from centosplus that you want. In this case php.

Next open

nano /etc/yum.repos.d/CentOS-Base.repo

You should have something that looks like this.

[base]
name=CentOS-$releasever - Base
mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=os
#baseurl=http://mirror.centos.org/centos/$releasever/os/$basearch/
gpgcheck=1
gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-centos4
priority=1

#released updates
[updates]
name=CentOS-$releasever - Updates
mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=updates
#baseurl=http://mirror.centos.org/centos/$releasever/updates/$basearch/
gpgcheck=1
gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-centos4
priority=1

#packages used/produced in the build but not released
[addons]
name=CentOS-$releasever - Addons
mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=addons
#baseurl=http://mirror.centos.org/centos/$releasever/addons/$basearch/
gpgcheck=1
gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-centos4

#additional packages that may be useful
[extras]
name=CentOS-$releasever - Extras
mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=extras
#baseurl=http://mirror.centos.org/centos/$releasever/extras/$basearch/
gpgcheck=1
gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-centos4

#additional packages that extend functionality of existing packages
[centosplus]
name=CentOS-$releasever - Plus
mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=centosplus
#baseurl=http://mirror.centos.org/centos/$releasever/centosplus/$basearch/
gpgcheck=1
enabled=0
gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-centos4

#contrib - packages by Centos Users
[contrib]
name=CentOS-$releasever - Contrib
mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=contrib
#baseurl=http://mirror.centos.org/centos/$releasever/contrib/$basearch/
gpgcheck=1
enabled=0
gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-centos4

You now need to enable the centosplus repositiory. Also make sure that the priority is 2. It should now look like this.

[centosplus]
name=CentOS-$releasever - Plus
mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=centosplus
#baseurl=http://mirror.centos.org/centos/$releasever/centosplus/$basearch/
gpgcheck=1
enabled=1
gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-centos4
priority=2
protect=1

Now you need to exclude php from all the other active repositories so that php5 from centosplus is installed. This is done by adding the following line to each of the other repository

exclude=php*

The final file should look like this.

# CentOS-Base.repo
#
# This file uses a new mirrorlist system developed by Lance Davis for CentOS.
# The mirror system uses the connecting IP address of the client and the
# update status of each mirror to pick mirrors that are updated to and
# geographically close to the client. You should use this for CentOS updates
# unless you are manually picking other mirrors.
#
# If the mirrorlist= does not work for you, as a fall back you can try the
# remarked out baseurl= line instead.
#
#

[base]
name=CentOS-$releasever - Base
mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=os
#baseurl=http://mirror.centos.org/centos/$releasever/os/$basearch/
gpgcheck=1
gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-centos4
priority=1
protect=1
exclude=php*

#released updates
[update]
name=CentOS-$releasever - Updates
mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=updates
#baseurl=http://mirror.centos.org/centos/$releasever/updates/$basearch/
gpgcheck=1
gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-centos4
priority=1
protect=1
exclude=php*

#packages used/produced in the build but not released
[addons]
name=CentOS-$releasever - Addons
mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=addons
#baseurl=http://mirror.centos.org/centos/$releasever/addons/$basearch/
gpgcheck=1
gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-centos4
priority=1
protect=1
exclude=php*

#additional packages that may be useful
[extras]
name=CentOS-$releasever - Extras
mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=extras
#baseurl=http://mirror.centos.org/centos/$releasever/extras/$basearch/
gpgcheck=1
gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-centos4
priority=1
protect=1
exclude=php*

#additional packages that extend functionality of existing packages
[centosplus]
name=CentOS-$releasever - Plus
mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=centosplus
#baseurl=http://mirror.centos.org/centos/$releasever/centosplus/$basearch/
gpgcheck=1
enabled=1
gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-centos4
priority=2
protect=1

#contrib - packages by Centos Users
[contrib]
name=CentOS-$releasever - Contrib
mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=contrib
#baseurl=http://mirror.centos.org/centos/$releasever/contrib/$basearch/
gpgcheck=1
enabled=0
gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-centos4
priority=2
protect=1

Save the changes and update

yum update

You should see that centosplus is now part of your repositories and see something like the following

update 100% |=========================| 951 B 00:00
base 100% |=========================| 1.1 kB 00:00
centosplus 100% |=========================| 951 B 00:00
addons 100% |=========================| 951 B 00:00
extras 100% |=========================| 1.1 kB 00:00

Yum should finally prompt you to install the updates for php5. Don’t forget to restart apache to change it from using php4 to php5.

Updates:
A couple of quick things to note with upgrading:
1. php4 PEAR::MAIL is not compatible with php5 so you will need to upgrade it as well.
2. Your apache php.conf file will be overwritten. This last issue caught me out as I had apache set up to parse .html for php includes – the upgrade disable this. I guess the moral is test, test and test again after upgrading.

Set the localhost parameter when using PEAR::Mail

If you are using the PEAR:Mail php function to send emails from your server remember to set the localhost parameter (ie $params[“localhost”]=’yourhost.com’;). If you don’t set it then the originating server will be “localhost”. While this won’t stop the email being sent, spamassassin will mark the message as spam – not good if you want your emails to be received.

This little gotcha recently bit me. I hadn’t set the localhost parameter and only noticed when I had upgraded spamassassin and found my test emails ending up in my junk mail folder.

As for why you might want to use PEAR::Mail over the normal php mail() function the main reason is you can control which smtp server your mail is sent out over. This control is very useful if you are testing your system on one server and sending out the emails via another server.

How to stop ssh being hammered by script kiddies

If you ever look at your server logs you will see hundred (if not thousands) of attempts by the script kiddies trying to log in to ssh. On my main linux server I get around 200 attempts a day. Below is a part of a typical days pounding.

Active System Attack Alerts
=-=-=-=-=-=-=-=-=-=-=-=-=-=
Sep 12 11:06:14 226 portsentry[2618]: attackalert: TCP SYN/Normal scan from host: rrcs-64-183-196-194.sw.biz.rr.com/64.183.196.194 to TCP port: 22
Sep 12 11:06:14 226 portsentry[2618]: attackalert: Host 64.183.196.194 has been blocked via wrappers with string: "ALL: 64.183.196.194"
Sep 12 11:06:14 226 portsentry[2618]: attackalert: TCP SYN/Normal scan from host: rrcs-64-183-196-194.sw.biz.rr.com/64.183.196.194 to TCP port: 22
Sep 12 11:06:14 226 portsentry[2618]: attackalert: Host: rrcs-64-183-196-194.sw.biz.rr.com/64.183.196.194 is already blocked Ignoring
Sep 12 11:06:14 226 portsentry[2618]: attackalert: TCP SYN/Normal scan from host: rrcs-64-183-196-194.sw.biz.rr.com/64.183.196.194 to TCP port: 22
Sep 12 11:06:14 226 portsentry[2618]: attackalert: Host: rrcs-64-183-196-194.sw.biz.rr.com/64.183.196.194 is already blocked Ignoring
Sep 12 11:06:15 226 portsentry[2618]: attackalert: TCP SYN/Normal scan from host: rrcs-64-183-196-194.sw.biz.rr.com/64.183.196.194 to TCP port: 22
Sep 12 11:06:15 226 portsentry[2618]: attackalert: Host: rrcs-64-183-196-194.sw.biz.rr.com/64.183.196.194 is already blocked Ignoring
Sep 12 11:06:15 226 portsentry[2618]: attackalert: TCP SYN/Normal scan from host: rrcs-64-183-196-194.sw.biz.rr.com/64.183.196.194 to TCP port: 22
Sep 12 11:06:15 226 portsentry[2618]: attackalert: Host: rrcs-64-183-196-194.sw.biz.rr.com/64.183.196.194 is already blocked Ignoring
Sep 12 11:06:15 226 portsentry[2618]: attackalert: TCP SYN/Normal scan from host: rrcs-64-183-196-194.sw.biz.rr.com/64.183.196.194 to TCP port: 22
Sep 12 11:06:15 226 portsentry[2618]: attackalert: Host: rrcs-64-183-196-194.sw.biz.rr.com/64.183.196.194 is already blocked Ignoring
Sep 12 11:06:15 226 portsentry[2618]: attackalert: TCP SYN/Normal scan from host: rrcs-64-183-196-194.sw.biz.rr.com/64.183.196.194 to TCP port: 22
Sep 12 11:06:15 226 portsentry[2618]: attackalert: Host: rrcs-64-183-196-194.sw.biz.rr.com/64.183.196.194 is already blocked Ignoring
Sep 12 11:06:15 226 portsentry[2618]: attackalert: TCP SYN/Normal scan from host: rrcs-64-183-196-194.sw.biz.rr.com/64.183.196.194 to TCP port: 22
Sep 12 11:06:15 226 portsentry[2618]: attackalert: Host: rrcs-64-183-196-194.sw.biz.rr.com/64.183.196.194 is already blocked Ignoring
Sep 12 12:10:30 226 portsentry[2618]: attackalert: TCP SYN/Normal scan from host: dsl-TN-static-140.246.22.125.airtelbroadband.in/125.22.246.140 to TCP port: 22
Sep 12 12:10:30 226 portsentry[2618]: attackalert: Host 125.22.246.140 has been blocked via wrappers with string: "ALL: 125.22.246.140"
Sep 12 12:10:30 226 portsentry[2618]: attackalert: TCP SYN/Normal scan from host: dsl-TN-static-140.246.22.125.airtelbroadband.in/125.22.246.140 to TCP port: 22
Sep 12 12:10:30 226 portsentry[2618]: attackalert: Host: dsl-TN-static-140.246.22.125.airtelbroadband.in/125.22.246.140 is already blocked Ignoring
Sep 12 12:10:30 226 portsentry[2618]: attackalert: TCP SYN/Normal scan from host: dsl-TN-static-140.246.22.125.airtelbroadband.in/125.22.246.140 to TCP port: 22
Sep 12 12:10:30 226 portsentry[2618]: attackalert: Host: dsl-TN-static-140.246.22.125.airtelbroadband.in/125.22.246.140 is already blocked Ignoring
Sep 12 16:04:44 226 portsentry[2618]: attackalert: TCP SYN/Normal scan from host: 82.138.34.109/82.138.34.109 to TCP port: 22
Sep 12 16:04:44 226 portsentry[2618]: attackalert: Host 82.138.34.109 has been blocked via wrappers with string: "ALL: 82.138.34.109"

As you can see the kiddies are trying to ssh connect on port 22. One of the simplest things you can do to improve ssh security is to move the ssh port away from the default port 22 and close port 22 (why you are are at you might as well close the telnet port 23).

To do this open the sshd_config file (I like to use nano) and change the default port from 22 to anything else that is not being used (under 1024 is a good idea). The sshd_config file is likely to be located in /etc/ssh but if not look for it by using find (ie use “find / -name ‘sshd_config’ “.

Restart sshd and log in using ssh -p [new port] user@serveraddress (eg ssh -p 999 daniel@tillett.com). This will solve most of the problems but it is a good idea to refuse all connections on port 22. I will leave how to do that for another post.

I should add this is not a substitute for security, but it does stop your logs from being filled with garbage.

Removing all files older than X days

This is just a little linux command line hack for removing all files older than X days (Substitute the X for the number of days):

find /[path]/* -mtime +X -exec rm -rf {} \;

eg “find /var/www/html/* -mtime +3 -exec rm -rf {} \;” to delete all files in the html directory older than 3 days.

Before running this you can also check what will be deleted by running the following:

find /[path]/* -mtime +X -exec ls -la {} \;