CVS: cvsweb con y sin chroot

CVSweb es un cgi que podemos instalar en el httpd para acceder al código fuente de nuestros repositorios y módulos cvs navegando por ellos como si de una página web se tratara (ejemplo).

Al ser un .cgi lo lógico es que vaya en el directorio cgi-bin/ del servidor, pero esto puede presentar más de un problema, bien porque no funcionen enlaces internos, hojas de estilo... y nos obligue a colocar ciertos archivos en ubicaciones predeterminadas que no gustan demasiado, bien porque queramos poner restricciones de acceso a través de .htaccess y presente un inconveniente dentro de cgi-bin.

Instalación

Por ello intentaremos instalar cvsweb fuera de su ubicación determinada y con unas condiciones especiales. Descomprimimos la descarga en donde la queramos instalar. Antes de continuar damos permisos de ejecución al cgi dentro del directorio destino, por ejemplo /var/www/dev.midominio.com/. Hecho esto modificamos el VirtualHost del dominio para que permita ejecutar cgi-scripts:
<VirtualHost *:80>
	...
	<Directory /var/www/dev.midominio.com/ >
		Options +ExecCGI
		AddHandler cgi-script cgi pl
	</Directory>
</VirtualHost>
Ahora colocamos cvsweb.cgi -con los convenientes permisos de ejecución si no queremos obtener un Error 500 ;)- y cvsweb.conf en ese directorio comprobando que ambos se ven (en versiones antiguas con estos 2 ficheros bastaba, ahora es posible que también haya -al menos- un directorio css/):
# grep cvsweb.conf cvsweb.cgi | head -1
 for ("$mydir/cvsweb.conf", 'cvsweb.conf') {
Ajustando la ruta si fuera necesario (en este caso están en la misma ubicación). Editamos también cvsweb.conf para configurar la ruta en la que está el repositorio (/cvs/public en este entorno):
# grep Repository cvsweb.conf | more
        'public' => ['Public Repository', '/cvs/public'],
En el siguiente reinicio del servidor web ya estaría todo funcionando.

Con contraseña

Ahora queremos proteger nuestro repositorio con una contraseña para que nadie espíe el código fuente :P, nos servimos del típico .htaccess:
AuthName "Zona Restringida"
AuthType Basic
AuthUserFile conf/users

require user miusuario
Y creamos el archivo conf/users con htpasswd:
# htpasswd -c conf/users miusurio      
New password: 
Re-type new password: 
#

Dos repositorios

Para rizar el rizo ahora quiero dos repositorios, uno con código fuente visible para todo el mundo y otro solo para desarrolladores de ciertos módulos, con lo que, dentro del mismo Virtualhost creo dos carpetas distintas public/ y private/.

Las directivas anteriores (Options +ExecCGI y AddHandler cgi-script cgi pl) están aplicadas a todo el dominio (subdominio en este caso) así que no tendré problema. Dentro de esas carpetas ubicamos los cvsweb y el .htaccess donde corresponda:
# ls -las private/
  4 drwxr-xr-x  2 root  r0sk      512 Nov 14 18:22 .
  4 drwxr-xr-x  4 root  r0sk      512 Nov 12 20:37 ..
  4 -rw-r--r--  1 www   www        88 Nov 12 19:00 .htaccess
192 -r-xr-xr-x  1 root  r0sk    96278 Nov 12 20:06 cvsweb.cgi
 32 -rw-r--r--  1 root  daemon  15557 Nov 12 20:07 cvsweb.conf

# ls -las public/
  4 drwxr-xr-x  2 root  r0sk      512 Nov 12 20:06 .
  4 drwxr-xr-x  4 root  r0sk      512 Nov 12 20:37 ..
192 -r-xr-xr-x  1 root  r0sk    96278 Nov 12 20:06 cvsweb.cgi
 32 -rw-r--r--  1 root  daemon  15557 Nov 12 20:06 cvsweb.conf
Private está protegido por contraseña (como hemos visto en el apartado anterior) mientras que Public está abierto a todo el mundo. Ojo, estoy utilizando dos repositorios cvs distintos:
# cat private/cvsweb.conf | grep Repository
'private' => ['Private Repository', '/cvs/private'],

# cat public/cvsweb.conf | grep Repository
        'public'  => ['Public Repository', '/cvs/public'],

Chrooted httpd

Si tu servidor web está enjaulado -chrooted- (como por ejemplo el httpd de OpenBSD) tendrás un poco más de trabajo copiando las librerías necesarias dentro del chroot para que todo funcione. A mayores todas las rutas de configuración serán absolutas al chroot (siendo /var/www la jaula, /var/www/conf pasa a ser /conf, etc). Instrucciones de enjaulado:
$ cd /var/www
# mkdir {tmp,usr}
# chown www:www tmp

$ cd /var/www/usr
# mkdir -p {bin,lib,libdata/perl5,libexec}

$ cd /var/www/usr/libdata/perl5
# mkdir -p {File,IPC,Time,warnings,`machine`-openbsd/5.8.6}

$ cd /var/www/usr/bin
# cp -p /usr/bin/{co,cvs,diff,perl,rcsdiff,rlog,uname} .

$ cd /var/www/usr/lib
# cp -p /usr/lib/lib{c,crypto,des,gssapi,krb5,m,perl,util,z}.so* .

$ cd /var/www/usr/libexec
# cp -p /usr/libexec/ld.so .

$ cd /var/www/usr/libdata/perl5
# cp -p /usr/libdata/perl5/{Carp,Exporter,Symbol,base,integer}.pm .
# cp -p /usr/libdata/perl5/{strict,warnings,vars}.pm .
# cp -p /usr/libdata/perl5/File/Basename.pm ./File/
# cp -p /usr/libdata/perl5/IPC/Open{2,3}.pm ./IPC/
# cp -p /usr/libdata/perl5/Time/Local.pm ./Time/
# cp -p /usr/libdata/perl5/warnings/register.pm ./warnings/

$ cd /var/www/usr/libdata/perl5/`machine`-openbsd/5.8.6
# cp -p /usr/libdata/perl5/`machine`-openbsd/5.8.6/{Config,Cwd}.pm .
Cuidado en los ficheros de configuración:
/var/www/cgi-bin/cvsweb:
  for ("$mydir/cvsweb.conf", '/var/www/conf/cvsweb/cvsweb.conf') {   (default)
  for ("$mydir/cvsweb.conf", '/conf/cvsweb/cvsweb.conf') {           (chroot)
/var/www/conf/cvsweb/cvsweb.conf:
  @CVSrepositories = (
    'local'   => ['Local Repository', '/home/cvs'],   (default)
    'local'   => ['Local Repository', '/cvs'],        (chroot)

    $mime_types = '/var/www/conf/mime.types';         (default)
    $mime_types = '/conf/mime.types';                 (chroot)

Screenshot

CVSweb
cvsweb en acción
openbsd sysadmin

About the author

Óscar
has doubledaddy super powers, father of Hugo and Nico, husband of Marta, *nix user, Djangonaut and open source passionate.