Log in
R. Kris Hardy Photo

R. Kris Hardy

December 12, 2009

Subversion Fix: svn copy causes “Repository moved permanently to ‘…’; please relocate

Filed under: Articles,Debugging — Tags: , , , — Kris @ 12:54 pm

Background

Subversion is a version control system. It can run as either it’s own server (svnserve), or as an Apache module (mod_dav_svn.so).

When using the mod_dav_svn module for Apache, and doing an svn copy operation on the repository itself can fail if the VirtualHost configuration for subversion is not correct. Put simply, if Apache itself and mod_dav_svn are serving content from the same path, then conflicts can occur. Apache can get confused if it attempts to serve a physical file instead of routing the request through mod_dav_svn.

“svn copy …” operations will fail, while “svn update …”, “svn commit …”, and “svn checkout …” operations work fine.

Detail of the problem, diagnosing the problem, and the fix are below.

(more… >>)

Technorati Tags: , , ,

December 10, 2009

Permission Denied (13) When Opening Socket in PHP & Apache

This post covers two cases that I’ve run into that cause Permission Denied (13) errors when opening sockets in PHP.

Situation #1:  SELinux denies httpd from opening socket

I ran into this simple, but annoying, problem after I migrated my development workstation to Fedora 12.

Problem:

A large PHP application that I have developed at Submerged Solutions (SandPiper Accounting) began throwing Permission Denied (13) system exceptions when attempting to send mail through Zend Framework’s Zend_Mail library.

All the phpunit unit tests worked fine and could send e-mail, but would fail when the usability tests started and any HTTP requests that sent e-mail were handled through Apache.

The Apache instance was being run as user apache / group apache, and php (mod_php) is run as user apache / group apache.

The exception occurred in Zend_Mail_Protocol_Abstract->_connect(), immediately following the socket opening call “stream_socket_client(…)”.

File: Zend/Mail/Protocol/Abstract.php; Line 224

50: abstract class Zend_Mail_Protocol_Abstract
51: {
...
218: protected function _connect($remote)
219: {
220: $errorNum = 0;
221: $errorStr = '';
222:
223: // open connection
224: $this->_socket = @stream_socket_client($remote, $errorNum, $errorStr, self::TIMEOUT_CONNECTION);
225: ...

fopen() calls using http and ftp protocols also failed:

Warning: fopen(…) [function.fopen]: failed to open stream: Permission denied in …

The fix:

The problem turned out to be the “httpd_can_network_connect” SELinux setting that is on by default in Fedora 12.

In a shell console, run as root:

# /usr/sbin/setsebool httpd_can_network_connect=1

Thanks to durwood, who pointed this out on PHP.net.

“Bug” Report at RedHat.com.

More info on SELinux.

Situation #2: PHP forbids opening socket to 255.255.255.255

A reader of this blog brought a problem of his to me.  I had never seen it before, so it was definitely interesting.

Problem:

This reader was using this PHP script that he had found to do Wake-on-LAN pings on his local network.  The script worked fine in Windows, but failed on his Fedora 10 server.  The error he received was Permission Denied (13).

His WoL packets were sent via udp to the broadcast address 255.255.255.255.  This worked fine in Windows, but failed in Linux.

His server’s PHP installation had socket support enabled, and udp was a registered stream socket transport.

His SELinux was disabled, so Situation #1 did not apply to him.

This is probably distribution specific.  I’m running Fedora 12, and had no such issues, whereas the person facing this problem was running Fedora 10.

Solution:

Either PHP or the the user running the PHP instance (“apache” in this case), was being forbidden from opening sockets to 255.255.255.255.  It turns out this is somewhat common.  Even when running the script as “root”, you can still get permission denied errors.

I came upon this short comment on php.net about someone else getting permission denied errors on socket_connect() calls.

There was also this comment which showed an easy way to get the broadcast address for the computer’s network interface. This method seems to work, however, it is limited to Linux since it relies upon the following gnu utilities: ifconfig, grep and cut.  It may work if you compile Windows ports to these utilities, or use cygwin.  (Note: The code snippet at PHP.net has errors.  A revised script is pasted below.)

Here’s the way to get the broadcast address:

exec("ifconfig | grep Bcast | cut -d \":\" -f 3 | cut -d \" \" -f 1",$addr);
$addr=array_flip(array_flip($addr));

By getting the broadcast address of the network interface, you can send Wake-on-LAN magic packets to that address rather than to 255.255.255.255.  Doing this, the sockets can be connected successfully, and the permission denied errors were resolved.

Here’s the “fixed” code from PHP.net.  It hasn’t been tested, so you very well may need to modify it for your needs.

<?php
/**
 * Wake-on-LAN
 *
 * @return boolean
 *   TRUE:    Socked was created successfully and the message has been sent.
 *   FALSE:   Something went wrong
 *
 * @param string|array  $mac   You will WAKE-UP this WOL-enabled computer, you
 *                             need to add the MAC-address here. Mac can be
 *                             array too.
 *
 * @param string|array  $addr  You will send and broadcast to this address.
 *                             Normally you need to use the 255.255.255.255
 *                             address, so I made it as the default. You don't need to do anything with this.
 *
 *                             If you get permission denied errors when using
 *                             255.255.255.255 have permission denied problems
 *                             you can set $addr = false to get the broadcast
 *                             address from the network interface using the
 *                             ifconfig command.
 *
 *                             $addr can be array with broadcast IP values
 *
 * Example 1:
 *   When the message has been sent you will see the message "Done...."
 *   if ( wake_on_lan('00:00:00:00:00:00'))
 *      echo 'Done...';
 *   else
 *      echo 'Error while sending';
 */

function wake_on_lan($mac, $addr=false, $port=7) {
    if ($addr === false){
        exec("ifconfig | grep Bcast | cut -d \":\" -f 3 | cut -d \" \" -f 1",$addr);
        $addr=array_flip(array_flip($addr));
    }
    if(is_array($addr)){
        $last_ret = false;
        for ($i = 0; $i < count($addr); $i++)
            if ($addr[$i] !== false) {
                $last_ret = wake_on_lan($mac, $addr[$i], $port);
            }
        return $last_ret;
    }
    if (is_array($mac)){
        $ret = array();
        foreach($mac as $k =< $v)
            $ret[$k] = wake_on_lan($v, $addr, $port);
        return $ret;
    }
    //Check if it's an real MAC-address and split it into an array
    $mac = strtoupper($mac);
    if (!preg_match("/([A-F0-9]{1,2}[-:]){5}[A-F0-9]{1,2}/", $mac, $maccheck))
        return false;
    $addr_byte = preg_split("/[-:]/", $maccheck[0]);

    //Creating hardware adress
    $hw_addr = '';
    for ($a = 0; $a < 6; $a++)//Changing mac adres from HEXEDECIMAL to DECIMAL
        $hw_addr .= chr(hexdec($addr_byte[$a]));

    //Create package data
    $msg = str_repeat(chr(255),6);
    for ($a = 1; $a <= 16; $a++)
        $msg .= $hw_addr;
    //Sending data
    if (function_exists('socket_create')){
        //socket_create exists
        $sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);    //Can create the socket
        if ($sock){
            $sock_data = socket_set_option($sock, SOL_SOCKET, SO_BROADCAST, 1); //Set
            if ($sock_data){
                $sock_data = socket_sendto($sock, $msg, strlen($msg), 0, $addr,$port); //Send data
                if ($sock_data){
                    socket_close($sock); //Close socket
                    unset($sock);
                    return true;
                }
            }
        }
        @socket_close($sock);
        unset($sock);
    }
    $sock=fsockopen("udp://" . $addr, $port);
    if($sock){
        $ret=fwrite($sock,$msg);
        fclose($sock);
    }
    if($ret)
        return true;
    return false;
}

if (@wake_on_lan('00:00:00:00:00:00')) {
    echo 'Done...';
} else {
    echo 'Error while sending';
}
?>

Technorati Tags: , , , , , , ,


Powered by WordPress