
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Marble Station</title>
	<atom:link href="http://www.marblestation.com/?feed=rss2" rel="self" type="application/rss+xml" />
	<link>http://www.marblestation.com</link>
	<description>Web personal de Sergi Blanco Cuaresma</description>
	<lastBuildDate>Sat, 22 May 2010 14:55:18 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9</generator>
	<language>es</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Arcane Stones, juego para iPhone</title>
		<link>http://www.marblestation.com/?p=932</link>
		<comments>http://www.marblestation.com/?p=932#comments</comments>
		<pubDate>Mon, 03 Aug 2009 06:49:31 +0000</pubDate>
		<dc:creator>marble</dc:creator>
				<category><![CDATA[Castellano]]></category>

		<guid isPermaLink="false">http://www.marblestation.com/?p=932</guid>
		<description><![CDATA[Es fantástico ver como personas muy cercanas se animan con iniciativas empresariales, primero fue woices, luego Amplificat y ahora le toca el turno a Gerard Porto con la creación del juego Arcane Stones para iPhone:












Tanto la versión final como la demo la podéis obtener mediante iTunes   Enhorabuena Gerard y espero que sea el [...]]]></description>
			<content:encoded><![CDATA[<p>Es fantástico ver como personas muy cercanas se animan con iniciativas empresariales, primero fue <a href="http://woices.com/">woices</a>, luego <a href="http://amplifi.cat/">Amplificat</a> y ahora le toca el turno a Gerard Porto con la creación del juego <a href="http://appshopper.com/games/arcane-stones">Arcane Stones</a> para iPhone:</p>
<p><center></p>
<table border="0">
<tr>
<td>
<img src="http://farm4.static.flickr.com/3592/3783582681_50573f2ee5_m.jpg"/>
</td>
<td>
<img src="http://farm4.static.flickr.com/3570/3783582683_02a6ee2b9c_m.jpg"/>
</td>
</tr>
</table>
<p></center></p>
<p>Tanto la <a href="itms://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=322430848&#038;mt=8&#038;s=143441">versión final</a> como la <a href="itms://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=322925988&#038;mt=8&#038;s=143441">demo</a> la podéis obtener mediante iTunes <img src='http://www.marblestation.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' />  Enhorabuena Gerard y espero que sea el primero de muchos otros juegos!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.marblestation.com/?feed=rss2&amp;p=932</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Screen, múltiples consolas en una</title>
		<link>http://www.marblestation.com/?p=915</link>
		<comments>http://www.marblestation.com/?p=915#comments</comments>
		<pubDate>Sun, 14 Jun 2009 14:39:01 +0000</pubDate>
		<dc:creator>marble</dc:creator>
				<category><![CDATA[Castellano]]></category>

		<guid isPermaLink="false">http://www.marblestation.com/?p=915</guid>
		<description><![CDATA[Cuando accedemos remotamente por telnet o ssh a un sistema se suele obtener acceso a una única shell donde ejecutar comandos. Por ejemplo, si queremos ejecutar simultáneamente el lector de correo electrónico mutt y navegar por directorios para copiar o mover archivos, vamos a tener que realizar 2 conexiones para disponer de 2 shells: En [...]]]></description>
			<content:encoded><![CDATA[<p>Cuando accedemos remotamente por telnet o ssh a un sistema se suele obtener acceso a una única shell donde ejecutar comandos. Por ejemplo, si queremos ejecutar simultáneamente el <a href="http://www.marblestation.com/?p=246">lector de correo electrónico mutt</a> y navegar por directorios para copiar o mover archivos, vamos a tener que realizar 2 conexiones para disponer de 2 shells: En una ejecutaríamos mutt mientras usamos la otra para navegar por los directorios.</p>
<p>Adicionalmente, si perdemos la conexión con el servidor no podremos recuperar el estado en el que se encontraban las terminales. Por ejemplo, si estábamos comprimiendo un directorio y se corta la conexión, esta acción se quedará a medias y tendremos que repetirla.</p>
<p>Sin embargo, si hacemos uso de &#8216;<a href="http://es.wikipedia.org/wiki/GNU_Screen">screen</a>&#8216; podemos solventar de un plumazo esos dos inconvenientes:</p>
<ul>
<li>Únicamente nos bastará con realizar una conexión dado que este programa nos permite mantener diversas &#8220;ventanas&#8221; virtuales dentro de la misma terminal. El concepto es similar a cuando tenemos un único navegador con diferentes pestañas.</li>
<li>Si la conexión se pierde, screen continuará funcionando y al volver a reconectar con el servidor podremos recuperar el estado original</li>
</ul>
<p>Lo mejor es experimentar con screen para comprobar su utilidad:<br />
<span id="more-915"></span></p>
<pre>
sudo apt-get install screen
screen -R -D
</pre>
<p>El comando anterior restaurará la sesión anterior de screen en caso de existir o, de lo contrario, creará una sesión nueva. Acto seguido tendremos acceso a una shell como si nada hubiese ocurrido, no obstante ahora podemos utilizar diversas combinaciones de teclas para crear nuevas ventanas o realizar otras acciones:</p>
<ul>
<li>ctrl-a c</li>
<p>Crear una nueva ventana con una shell</p>
<li>ctrl-a k</li>
<p>Destruye la ventana actual</p>
<li>ctrl-a n<br />
ctrl-a p</li>
<p>Ir a la ventana siguiente o anterior</p>
<li>ctrl-a ctrl-a</li>
<p>Ir a la última ventana visualizada</p>
<li>ctrl-a A</li>
<p>Cambiar el título de la ventana actual</p>
<li>ctrl-a ESC</li>
<p>Ver el historial (scrolling buffer)</p>
<li>ctrl-a x</li>
<p>Bloquea terminal</p>
<li>ctrl-a d</li>
<p>Desasignar screen (recuperar después con screen -R -D)
</ul>
<p>Adicionalmente, podemos realizar pantallazos o llevar un registro de todos los comandos que ejecutamos:</p>
<ul>
<li>ctrl-a h</li>
<p>Guarda pantallazo en &#8220;hardcopy.n&#8221;</p>
<li>ctrl-a H</li>
<p>Inicia/para registro de la ventana actual en &#8220;screenlog.n&#8221;
</ul>
<p>O incluso podemos <a href="http://www.marblestation.com/?p=587">compartir una terminal entre diversos usuarios de forma remota con screen</a>.</p>
<p>Finalmente, si deseamos tener una barra inferior donde aparecerá el nombre de las diferentes ventanas, así como la carga del sistema y la hora actual (entre otras cosas), podemos modificar el fichero de configuración ~/.screenrc:</p>
<pre>
screen -t shell 0
#screen -t shell 0 motd+shell
#screen -t shell2    1
#screen -t server    2
#screen -t Mail 9   tail -f /var/log/messages

select 0
shelltitle "shell"

# skip the startup message
startup_message off

# go to home dir
chdir

# Automatically detach on hangup.
autodetach on

# Change default scrollback value for new windows
defscrollback 1000

# Turns off alternate screen switching in xterms,
# so that text in screen will go into the xterm's scrollback buffer:
termcapinfo xterm* ti@:te@
altscreen on

# start with visual bell as default
vbell on
vbell_msg "bell on %t (%n)"
activity "Activity in %t(%n)"

# Run a screensaver if there's nothing happening for a while.
#idle 600 eval "screen cmatrix -f -o -u 10" "idle 0"
idle 600 lockscreen

### White
#caption always "%{kW}%?%-Lw%?%{bw}%n*%f %t%?(%u)%?%{kW}%?%+Lw%? %= %{= Wk}%110`%109`%111` %H load: %l | %D %d-%m-%Y %0c:%s"

### Black
caption always "%{wk}%?%-Lw%?%{bw}%n*%f %t%?(%u)%?%{wk}%?%+Lw%? %= %{= kw}%110`%109`%111` %H load: %l | %D %d-%m-%Y %0c:%s"
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.marblestation.com/?feed=rss2&amp;p=915</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Vim, guía de referencia rápida</title>
		<link>http://www.marblestation.com/?p=910</link>
		<comments>http://www.marblestation.com/?p=910#comments</comments>
		<pubDate>Sun, 07 Jun 2009 15:44:03 +0000</pubDate>
		<dc:creator>marble</dc:creator>
				<category><![CDATA[Castellano]]></category>

		<guid isPermaLink="false">http://www.marblestation.com/?p=910</guid>
		<description><![CDATA[Vim (Vi IMproved) es uno de los mejores editores que existen para consola (aunque también hay una versión gráfica). Destaca por su simplicidad y la posibilidad de trabajar sin tener que levantar las manos del teclado, no obstante la curva de aprendizaje inicial es algo elevada y esto puede frenar a algunos usuarios.
Por defecto Ubuntu [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.vim.org/">Vim</a> (Vi IMproved) es uno de los mejores editores que existen para consola (aunque también hay una versión gráfica). Destaca por su simplicidad y la posibilidad de trabajar sin tener que levantar las manos del teclado, no obstante la curva de aprendizaje inicial es algo elevada y esto puede frenar a algunos usuarios.</p>
<p>Por defecto Ubuntu instala una versión reducida (tiny) de este editor que no es tan configurable como la versión completa, así que antes de empezar nos aseguramos de tener esta última:</p>
<pre>
sudo aptitude install vim
</pre>
<p>A continuación creamos el fichero &#8216;/etc/vim/vimrc.local&#8217; (o ~/.vimrc si solo queremos que afecte nuestro usuario) con la siguiente configuración:<br />
<span id="more-910"></span></p>
<pre>
" When editing a file, always jump to the last cursor position
autocmd BufReadPost *
      \ if line("'\"") > 0 &#038;&#038; line ("'\"") &#60;= line("$") |
      \   exe "normal g'\"" |
      \ endif

" sw -> espacios de la indentacion
set sw=4

" tabulacion
set tabstop=4
set smarttab

" Reemplazar tabs con espacios
"set expandtab

" ignore case en las busquedas
set ic

" highlight search, incsearch
set hls is

" Mostrar siempre la linea actual
set ruler

" Coloreado
syntax on

" Lineas
"set number

"Sin beep ni aviso visual
"set vb t_vb=

"Sin beep
"set vb

" Configuración del explorador de ficheros (":Explore")
"""""""""""""""""""""
" Al abrir un fichero, hacerlo en la ventana actual
let g:netrw_browse_split=0

" Activar la ocultacion de ficheros
let g:netrw_hide=1

" Lista de ficheros a ocultar (separar por comas)
let g:netrw_list_hide='^\..*'

" Modo de lista larga (con detalles)
let g:netrw_longlist=1

" Ordenar por "name", "time", o "size"
let g:netrw_sort_by="name"

" Orden "normal" o "reverse"
let g:netrw_sort_direction="normal"
""""""""""""""""""

" Mostrar siempre la barra de tabs
set stal=2

" Remapeo de comandos
nmap :W :w
nmap :Q :q
nmap :WQ :wq

" tab navigation
:nmap &#60;C-p> :tabprevious&#60;cr>
:nmap &#60;C-n> :tabnext&#60;cr>
:nmap &#60;C-t> :tabnew&#60;cr>
:map &#60;C-c> :tabclose&#60;cr>

" No guardar fichero de backup *~
set nobackup
</pre>
<p>Por otra parte, si queremos utilizar la versión gráfica de vim instalaremos &#8220;vim-full&#8221;:</p>
<pre>
apt-get install vim-full
</pre>
<p>Y crearemos el fichero &#8216;/etc/vim/gvimrc.local&#8217; con la siguiente configuración:</p>
<pre>
" Indentación elegante
set smartindent

" Ocultar puntero del raton al escribir
set mousehide

" Color de fondo Negro, color de la letra blanco
hi Normal       guibg=Black guifg=White 

" Esquema de color
"colorscheme torte

if filereadable("/etc/vim/vimrc.local")
  source /etc/vim/vimrc.local
endif
</pre>
<h3>Introducción</h3>
<p>Para editar un archivo con Vim ejecutaremos:</p>
<pre>
vim nombre_archivo.txt
gvim nombre_archivo.txt
</pre>
<p>Es habitual que se tenga definido un alias de forma que cuando ejecutemos &#8220;vi&#8221;, realmente estemos ejecutando &#8220;vim&#8221;:</p>
<pre>
alias vi='vim'
</pre>
<p>Este texto debe ser incluido en los archivos .bashrc y .bash_profile del directorio personal del usuario (cd $HOME).</p>
<p>Una vez tenemos abierto vim y estamos editando un archivo debemos conocer diversos comandos para poder utilizar el entorno. El editor se puede encontrar en 3 modos diferentes:</p>
<ul>
<li>Modo normal (Normal mode): Se pueden utilizar ciertas combinaciones de teclas para realizar ciertas acciones. Para acceder a este modo presionar escape.</li>
<li>Modo inserción (Insertion mode): Se puede insertar (insert) o sobreescribir el texto (append). Para acceder a este modo presionar &#8216;i&#8217;, &#8216;a&#8217; o la tecla &#8216;insert&#8217; (1 vez = insert, 2 veces = append).</li>
<li>Modo comando (Command mode): Se puede utilizar cualquier comando SED además de funciones propias de Vim.  Para acceder a este modo se debe estar en modo normal y pulsar &#8216;:&#8217;, a continuación se escribirá nuestra petición.</li>
<li>Modo visual (visual mode): Se puede selecionar texto para tratarlo en conjunto. Para acceder a este modo se debe estar en modo normal y pulsar &#8216;v&#8217;.</li>
</ul>
<h3>Modo Normal</h3>
<ul>
<li> Desplazamiento con los cursores del teclado o con h (izquierda), j (arriba), k (abajo) y l (derecha)</li>
<li> Última línea</li>
<p>G</p>
<li> Primera línea</li>
<p>gg</p>
<li> Deshacer</li>
<p>u</p>
<li> Rehacer</li>
<p>CTRL+r</p>
<li> Buscar un texto</li>
<p>/texto[ENTER]</p>
<li> Repetir última búsqueda</li>
<p>n</p>
<li> Repetir última búsqueda en sentido contrario</li>
<p>N</p>
<li> Dividir la pantalla horizontalmente en 2:</li>
<p>CTRL+ws</p>
<li> Dividir la pantalla verticalmente en 2:</li>
<p>CTRL+wv</p>
<li> Crear un nuevo archivo en una pantalla dividida horizontalmente:</li>
<p>CTRL+wn</p>
<li> Cerrar la división actual</li>
<p>CTRL+wq</p>
<li> Moverse a la ventana de arriba (j), abajo (k), izquierda (h) o derecha (l):</li>
<p>CTRL+w{j,k,h,l} ó CTRL+w{cursores del teclado}</p>
<li> Hacer todas las ventanas del mismo tamaño</li>
<p>CTRL+w=</p>
<li> Incrementar/Decrementar la altura de la ventana actual</li>
<p>CTRL+{+,-}</p>
<li> Nueva pestaña</li>
<p>CTRL+t</p>
<li> Siguiente o anterior pestaña</li>
<p>CTRL+n<br />
CTRL+p</p>
<li> Cerrar pestaña</li>
<p>CTRL+c</p>
</ul>
<h3>Modo Inserción</h3>
<ul>
<li> Autocompletar palabra en base al texto ya existente</li>
<p>CTRL+N y CTRL+P (p.ej. &#8220;hola hCTRL+N&#8221; resultado &#8220;hola hola&#8221;)
</ul>
<h3>Modo Comando</h3>
<p><i>Pulsar [ENTER] después de cada comando</i></p>
<ul>
<li>Ir a la linea 25</li>
<p>:25</p>
<li>Salir</li>
<p>:q</p>
<li>Salir cerrando todos los ficheros abiertos</li>
<p>:qa</p>
<li>Guardar</li>
<p>:w</p>
<li>Salir guardando</li>
<p>:wq</p>
<li>Salir sin guardar</li>
<p>:q!</p>
<li>Guardar en fichero de solo lectura (sólo root)</li>
<p>:w!</p>
<li>Guardar con otro nombre</li>
<p>:w archivo</p>
<li>Editar archivo</li>
<p>:e archivo</p>
<li>Navegar a partir de un directorio</li>
<p>:e directorio<br />
:Explore</p>
<li>Substituir una cadena de texto A por B <i>(si alguna de estas cadenas contiene caracteres que tengan algun significado especial como por ejemplo &#8216;/&#8217; se debe anular antes la funcionalidad de este con \, por ejemplo, substituir los &#8216;/&#8217; por &#8216;.&#8217; seria :s/\//./)</i></li>
<p>:%s/A/B/ (p.ej. :s/hola/adios)</p>
<li>Substituir una cadena de texto A por B en todo el texto</li>
<p>:%s/A/B/g</p>
<li>Substituir una cadena de texto A por B entre la linea 2 y 10</li>
<p>:2,10s/A/B/g</p>
<li>Activar la inserción en &#8220;modo paste&#8221;, esto permite pegar cosas al documento (usando el ratón) de forma que no tabule lo que pegamos, ya que si ese texto ya esta tabulado lo único que hace es pegar desordenando el texto.</li>
<p>:set paste</p>
<li>Desactivar la inserción en &#8220;modo paste&#8221;</li>
<p>:set nopaste</p>
<li>Cortar las líneas que no caben en pantalla.</li>
<p>:set wrap</p>
<li>No cortar las líneas que no caben en pantalla</li>
<p>:set nowrap</p>
<li>Dividir pantalla horizontalmente</li>
<p>:split</p>
<li>Dividir pantalla verticalmente</li>
<p>:vsplit</p>
<li>Crear nueva pantalla dividida</li>
<p>:new</p>
<li>Quedarse solo con la ventana actual y ocultar el resto</li>
<p> <img src='http://www.marblestation.com/wp-includes/images/smilies/icon_surprised.gif' alt=':o' class='wp-smiley' /> nly</p>
<li>Listar todos los ficheros abiertos (buffers)</li>
<p>:files ó :buffers</p>
<li>Ir al buffer X (los numeros aparecen al hacer un :files o :buffers *en plural*)</li>
<p>:file X ó :buffer X</p>
<li>Ayuda</li>
<p>:help ó :help termino
</ul>
<h3>Modo Visual</h3>
<p>Como ya hemos comentado, para acceder a este modo se debe estar en modo normal y pulsar ‘v’. No obstante, si en lugar de &#8216;v&#8217; pulsamos &#8216;Ctrl+v&#8217; pasaremos al modo visual en bloque (permite seleccionar un bloque de texto por columnas en lugar de por filas).</p>
<ul>
<li>Seleccionar texto utilizando h(izquierda), j (arriba), k (abajo) y l (derecha) o con los cursores del teclado.</li>
<p></p>
<li>Es posible aplicar las mismas instrucciones vista en el modo comando y modo normal, pero esto solo se realizará sobre el texto seleccionado.</li>
<p></p>
<li>Si seleccionamos texto y pasamos a modo comando pulsando &#8216;:&#8217; se nos mostrar una linea como esta &#8220;:&#8217; &#60;,&#8217;>&#8221;, no debemos borrar estos símbolos ya que es la forma de reconocer vim que estamos aplicando el comando al texto seleccionado.</li>
<p></p>
<li>Copiar el texto selecionado</li>
<p>y</p>
<li>Cortar el texto seleccionado</li>
<p>d</p>
<li>Pegar el texto copiado o cortado. Debemos estar en modo normal, se pasará automáticamente a ese modo despues de copiar o cortar con &#8216;y&#8217; o &#8216;d&#8217;.</li>
<p>p</p>
</ul>
<h3>Corrector ortográfico</h3>
<p>Por defecto, vim dispone de corrector para Inglés pero quizás también nos interese tener para Castellano y Catalan:</p>
<pre>
sudo -s
cd /usr/share/vim/vimcurrent/spell
wget http://ftp.vim.org/vim/runtime/spell/es.latin1.spl
wget http://ftp.vim.org/vim/runtime/spell/es.latin1.sug
wget http://ftp.vim.org/vim/runtime/spell/es.utf-8.spl
wget http://ftp.vim.org/vim/runtime/spell/es.utf-8.sug                        

wget http://ftp.vim.org/vim/runtime/spell/ca.latin1.spl
wget http://ftp.vim.org/vim/runtime/spell/ca.latin1.sug
wget http://ftp.vim.org/vim/runtime/spell/ca.utf-8.spl
wget http://ftp.vim.org/vim/runtime/spell/ca.utf-8.sug
</pre>
<p>Una vez instalados los diccionarios, en modo comando:</p>
<ul>
<li>Activar corrector</li>
<p>:set spell</p>
<li>Desactivar corrector</li>
<p>:set nospell</p>
<li>Seleccionamos idioma</li>
<p>:setlocal spell spelllang=es<br />
:setlocal spell spelllang=ca<br />
:setlocal spell spelllang=en
</ul>
<p>Las palabras incorrectas se marcaran en color rojo y podremos interaccionar en modo normal:</p>
<ul>
<li>Siguiente palabra incorrecta</li>
<p>]s</p>
<li>Previa palabra incorrecta</li>
<p>[s</p>
<li>Sugerencias de corrección para una palabra</li>
<p>z=</p>
<li>Añadir una palabra al diccionario</li>
<p>zg</p>
<li>Borrar una palabra del diccionario</li>
<p>zw
</ul>
<p>En la página de <a href="http://www.vim.org/">Vim</a> se puede encontrar más información, incluso scripts que añaden funcionalidades interesantes.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.marblestation.com/?feed=rss2&amp;p=910</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Clases sobre mercados financieros</title>
		<link>http://www.marblestation.com/?p=904</link>
		<comments>http://www.marblestation.com/?p=904#comments</comments>
		<pubDate>Mon, 01 Jun 2009 13:03:05 +0000</pubDate>
		<dc:creator>marble</dc:creator>
				<category><![CDATA[Castellano]]></category>

		<guid isPermaLink="false">http://www.marblestation.com/?p=904</guid>
		<description><![CDATA[Uno de los aspectos en los que falla la educación básica (e incluso universitaria) es en la de proporcionar a los estudiantes las herramientas para entender como funciona el dinero. Estos conocimientos, que si son accesibles vía grado de administración de empresas o MBA, resultan fundamentales en una sociedad donde rigen las reglas de los [...]]]></description>
			<content:encoded><![CDATA[<p>Uno de los aspectos en los que falla la educación básica (e incluso universitaria) es en la de proporcionar a los estudiantes las herramientas para entender como funciona el dinero. Estos conocimientos, que si son accesibles vía grado de administración de empresas o MBA, resultan fundamentales en una sociedad donde rigen las reglas de los mercados financieros. Se puede discutir si esta es la mejor forma de organizar una sociedad o no, pero lo que esta claro es que es mejor conocer las reglas del juego porque hoy por hoy es lo que tenemos.</p>
<p>El profesor Xavier Puig de la <a href="http://www.upf.edu/es/">Universitat Pompeu Fabra</a> ha colgado un conjunto de clases muy ilustrativas sobre el funcionamiento básico de los mercados financieros (monetarios, renta fija/variable, divisas), derivados (futuros, opciones) y matemáticas financieras elementales (VAN, TIR):<br />
<span id="more-904"></span></p>
<p><b>Mercados financieros</b></p>
<ul>
<li><a href="http://sclipo.com/videos/view/introduccion-mercados-finacieros">Capítulo 1: Introducción a los mercados financieros</a></li>
<li><a href="http://sclipo.com/videos/view/el-precio-del-dinero-a-corto-y-largo-plazo">Capítulo 2: El precio del dinero a corto y largo plazo</a></li>
<li><a href="http://sclipo.com/videos/view/qua-es-y-qua-no-es-la-bolsa">Capítulo 3: Qué es y qué no es la bolsa</a></li>
<li><a href="http://sclipo.com/videos/view/qua-es-caro-y-qua-es-barato">Capítulo 4: Qué es caro y qué es barato</a></li>
<li><a href="http://sclipo.com/videos/view/per-y-rentabilidad-por-dividendos">Capítulo 5: PER y rentabilidad por dividendos</a></li>
</ul>
<p><b>Derivados: Futuros y opciones</b></p>
<ul>
<li><a href="http://sclipo.com/videos/view/postgrado-en-asesoramiento-financiero-capa-tulo-1">Capítulo 1: Introducción y conceptos básicos</a></li>
<li><a href="http://sclipo.com/videos/view/capitulo-2-especulacia-n-con-futuros-posicion-compradora">Capítulo 2: Especulación con futuros &#8211; Posición compradora</a></li>
<li><a href="http://sclipo.com/videos/view/capitulo-3-cobertura-con-futuros">Capítulo 3: Cobertura con futuros</a></li>
<li><a href="http://sclipo.com/videos/view/capitulo-4-operarativa-con-futuros-en-la-practica">Capítulo 4: Operativa con futuros en la prácticas</a></li>
<li><a href="http://sclipo.com/videos/view/capitulo-5-futuros-sobre-indices-bursatiles">Capítulo 5: Futuros sobre índices bursatiles</a></li>
<li><a href="http://sclipo.com/videos/view/capitulo-6-resumen-y-conclusiones-de-futuros">Capítulo 6: Resumen y conclusiones de futuros</a></li>
<li><a href="http://sclipo.com/videos/view/capitulo-7-introduccion-y-conceptos-basicos-de-opciones">Capítulo 7: Introducción y conceptos básicos de opciones</a></li>
<li><a href="http://sclipo.com/videos/view/capitulo-8-opciones-de-compra-a-call-optionsa">Capítulo 8: Opciones de compra / Call Options</a></li>
<li><a href="http://sclipo.com/videos/view/capa-tulo-9-opciones-de-venta-a-put-optionsa">Capítulo 9: Opciones de venta / Put Options</a></li>
</ul>
<p><b>Matemáticas financieras</b></p>
<ul>
<li><a href="http://sclipo.com/videos/view/matema-ticas-financieras-capa-tulo-1-introduccia-n">Capítulo 1: Introducción</a></li>
<li><a href="http://sclipo.com/videos/view/matema-ticas-financieras-capa-tulo-2-operaciones">Capítulo 2: Operaciones</a></li>
<li><a href="http://sclipo.com/videos/view/matema-tica-financiera-ba-sica-capa-tulo-3-van-formulacia-n-y-ca-lculo">Capítulo 3: VAN &#8211; Formulación y cálculo</a></li>
<li><a href="http://sclipo.com/videos/view/matema-tica-financiera-ba-sica-capa-tulo-4-van-uso-e-interpretacia-n">Capítulo 4: VAN &#8211; Uso e interpretación</a></li>
<li><a href="http://sclipo.com/videos/view/matema-tica-financiera-ba-sica-capa-tulo-6-tir-tasa-interna-de-rentabilidad">Capítulo 5: VAN &#8211; Un ejemplo</a></li>
<li><a href="http://sclipo.com/videos/view/matema-tica-financiera-ba-sica-capa-tulo-6-tir-tasa-interna-de-rentabilidad">Capítulo 6: TIR &#8211; Tasa interna de rentabilidad</a></li>
<li><a href="http://sclipo.com/videos/view/matema-tica-financiera-ba-sica-capa-tulo-7-tae-tasa-anual-equivalente">Capítulo 7: TAE &#8211; Tasa anual equivalente</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.marblestation.com/?feed=rss2&amp;p=904</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>DNI electrónico en Ubuntu GNU/Linux</title>
		<link>http://www.marblestation.com/?p=895</link>
		<comments>http://www.marblestation.com/?p=895#comments</comments>
		<pubDate>Sun, 31 May 2009 14:00:50 +0000</pubDate>
		<dc:creator>marble</dc:creator>
				<category><![CDATA[Castellano]]></category>

		<guid isPermaLink="false">http://www.marblestation.com/?p=895</guid>
		<description><![CDATA[Mediante lectores de tarjetas inteligentes como LTC31 podemos hacer que nuestro sistema lea los DNIs electrónicos que se emiten actualmente.
Vamos a configurar el sistema para que Ubuntu reconozca el dispositivo lector y podamos utilizarlo desde el navegador Firefox. Para ello, instalaremos los paquetes necesarios (muchos de los pasos que describo los he obtenido del artículo [...]]]></description>
			<content:encoded><![CDATA[<p>Mediante lectores de tarjetas inteligentes como <a href="http://www.c3po.es/ltc31.html">LTC31</a> podemos hacer que nuestro sistema lea los <a href="http://www.dnielectronico.es/">DNIs electrónicos</a> que se emiten actualmente.</p>
<p>Vamos a configurar el sistema para que Ubuntu reconozca el dispositivo lector y podamos utilizarlo desde el navegador Firefox. Para ello, instalaremos los paquetes necesarios (muchos de los pasos que describo los he obtenido del artículo <a href="http://universo.emergya.info/espacios/fontanon/dnie-y-lector-acr38-bajo-linux">DNIe y lector ACR38 bajo Linux</a>):<br />
<span id="more-895"></span></p>
<pre>
# Herramientas para que el sistema reconozca el lector
apt-get install pcscd pcsc-tools libccid opensc
# Integración con mozilla
apt-get install mozilla-opensc libnss3-tools
</pre>
<p>Adicionalmente, tendremos que instalar el driver concreto para poder leer DNIs que lo proporciona el ministerio del interior mediante la <a href="http://www.dnielectronico.es/descargas/PKCS11_para_Sistemas_Unix/distribuciones_linux.html">sección de descargas</a>. Por ejemplo, en mi caso descargo la versión de Ubuntu Intrepid 64 bits (funciona también en Jaunty):</p>
<pre>
wget http://www.dnielectronico.es/descargas/PKCS11_para_Sistemas_Unix/opensc-dnie_1.4.5-1_amd64_Ubuntu_Intrepid_Ibex.deb.tar
tar -xvf opensc-dnie_1.4.5-1_amd64_Ubuntu_Intrepid_Ibex.deb.tar
dpkg -i opensc-dnie_1.4.5-1_amd64_Ubuntu_Intrepid_Ibex.deb
</pre>
<p>A continuación podemos ejecutar &#8220;Aplicaciones &#8211; Oficina &#8211; Registrar módulo DNIe PKCS#11&#8243; para que se active el soporte en Firefox (módulo &#8220;/usr/lib/opensc-pkcs11.so&#8221;) y se añada el certificado de la Dirección General de la Policía.</p>
<p>Por otra parte, podemos comprobar si el sistema reconoce correctamente el lector. Lo conectamos, ejecutamos pcsc_scan e introducimos nuestro DNI:</p>
<pre>
# pcsc_scan
PC/SC device scanner
V 1.4.14 (c) 2001-2008, Ludovic Rousseau &#60;ludovic .rousseau@free.fr>
Compiled with PC/SC lite version: 1.4.99
Scanning present readers
0: C3PO LTC31 00 00

Sat May 30 17:00:41 2009
 Reader 0: C3PO LTC31 00 00
  Card state: Card removed,

Sat May 30 17:01:27 2009
 Reader 0: C3PO LTC31 00 00
  Card state: Card inserted,
  ATR: 3B 7F 38 00 00 00 6A 44 4E 49 65 20 02 4C 34 01 13 03 90 00

ATR: 3B 7F 38 00 00 00 6A 44 4E 49 65 20 02 4C 34 01 13 03 90 00
+ TS = 3B --> Direct Convention
+ T0 = 7F, Y(1): 0111, K: 15 (historical bytes)
  TA(1) = 38 --> Fi=744, Di=12, 62 cycles/ETU (57600 bits/s at 3.57 MHz)
  TB(1) = 00 --> VPP is not electrically connected
  TC(1) = 00 --> Extra guard time: 0
+ Historical bytes: 00 6A 44 4E 49 65 20 02 4C 34 01 13 03 90 00
  Category indicator byte: 00 (compact TLV data object)
    Tag: 6, len: A (pre-issuing data)
      Data: 44 4E 49 65 20 02 4C 34 01 13
    Mandatory status indicator (3 last bytes)
      LCS (life card cycle): 03 (Initialisation state)
      SW: 9000 (Normal processing.)

Possibly identified card (using /usr/share/pcsc/smartcard_list.txt):
3B 7F 38 00 00 00 6A 44 4E 49 65 20 02 4C 34 01 13 03 90 00
3B 7F 38 00 00 00 6A 44 4E 49 65 [1,2]0 02 4C 34 01 13 03 90 00
    DNI electronico (Spanish electronic ID card)

http://www.dnielectronico.es
</pre>
<p>Si todo ha ido bien, vayamos a intentar leer los certificados de nuestro DNI mediante Firefox. Lo abrimos con el lector conectado y vamos a &#8220;Editar &#8211; Preferencias &#8211; Avanzado &#8211; Cifrado &#8211; Ver Certificados &#8211; Sus Certificados&#8221;, donde nos pedirá el PIN de nuestro DNI.</p>
<p>Podemos comprobar la autenticación y firma mediante la página de prueba de la FNMT:</p>
<p><a href="https://av-dnie.cert.fnmt.es/compruebacert/compruebacert">https://av-dnie.cert.fnmt.es/compruebacert/compruebacert</a></p>
<p>Finalmente, determinados sitios web intentaran acceder al lector mediante Java (p.ej. entidades financieras como Bankinter o ING-Direct) y necesitaremos soporte para Java, para lo cual tendremos que escoger la versión abierta o la de Sun:</p>
<pre>
apt-get install openjdk-6-jre icedtea6-plugin
apt-get install sun-java6-jre sun-java6-plugin
</pre>
<p>Por desgracia, no he sido capaz de autenticarme en ninguna web que intente acceder al DNI mediante Java. Con la versión OpenJDK/IcedTea me salta un mensaje de error que no ofrece muchas pistas y con la versión de Sun me indica que el sistema operativo no es compatible.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.marblestation.com/?feed=rss2&amp;p=895</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Configuración de los permisos de UDEV para escáner HP ScanJet 5p en Ubuntu</title>
		<link>http://www.marblestation.com/?p=888</link>
		<comments>http://www.marblestation.com/?p=888#comments</comments>
		<pubDate>Sat, 30 May 2009 15:24:16 +0000</pubDate>
		<dc:creator>marble</dc:creator>
				<category><![CDATA[Castellano]]></category>

		<guid isPermaLink="false">http://www.marblestation.com/?p=888</guid>
		<description><![CDATA[Desde hace bastantes años tengo un escáner HP ScanJet 5p con una tarjeta SCSI PCI que funciona a la perfección en GNU/Linux. El dispositivo es utilizado por todos los usuarios del PC y por tanto necesito que todos tengan permiso para escanear. Sin embargo, el sistema UDEV de Ubuntu asocia automáticamente el escáner a un [...]]]></description>
			<content:encoded><![CDATA[<p>Desde hace bastantes años tengo un escáner HP ScanJet 5p con una tarjeta SCSI PCI que funciona a la perfección en GNU/Linux. El dispositivo es utilizado por todos los usuarios del PC y por tanto necesito que todos tengan permiso para escanear. Sin embargo, el sistema <a href="http://es.wikipedia.org/wiki/Udev">UDEV</a> de Ubuntu asocia automáticamente el escáner a un dispositivo &#8220;/dev/sg3&#8243; con permisos únicamente para root, por tanto el resto de usuario no pueden utilizarlo.</p>
<pre>
$ ls -la /dev/sg3
crw-rw----+ 1 root root 21, 2 2009-05-24 14:36 /dev/sg3
</pre>
<p>Para cambiar este comportamiento, vamos a extraer información sobre el dispositivo que en mi caso corresponde sg3 pero puede variar según la configuración (consultar <a href="http://es.wikipedia.org/wiki/Dmesg">dmesg</a>):<br />
<span id="more-888"></span></p>
<pre>
# udevadm info -a -p /sys/class/scsi_generic/sg3
...
looking at parent device '/devices/pci0000:00/0000:00:1e.0/0000:05:02.0/host10/target10:0:2/10:0:2:0':
    KERNELS=="10:0:2:0"
    SUBSYSTEMS=="scsi"
    DRIVERS==""
    ATTRS{device_blocked}=="0"
    ATTRS{type}=="3"
    ATTRS{scsi_level}=="3"
    ATTRS{vendor}=="HP      "
    ATTRS{model}=="C5110A          "
    ATTRS{rev}=="3701"
    ATTRS{state}=="running"
    ATTRS{timeout}=="0"
    ATTRS{iocounterbits}=="32"
    ATTRS{iorequest_cnt}=="0x7"
    ATTRS{iodone_cnt}=="0x7"
    ATTRS{ioerr_cnt}=="0x0"
    ATTRS{modalias}=="scsi:t-0x03"
    ATTRS{evt_media_change}=="0"
    ATTRS{queue_depth}=="2"
    ATTRS{queue_type}=="none"
...
</pre>
<p>A continuación, creamos una nueva regla UDEV en el fichero &#8220;/etc/udev/rules.d/99-personalizado.rules&#8221;:</p>
<pre>
# permissions for SCSI scanner
KERNEL=="sg[0-9]*", SUBSYSTEMS=="scsi", ATTRS{type}=="3", ATTRS{model}=="C5110A*", NAME="%k", SYMLINK="scanner", MODE="0660", GROUP="scanner"
</pre>
<p>En la regla estamos indicando que todos los dispositivos sgX (sg1, sg2, etc.), del tipo SCSI y modelo C5110A (información que coincide con el scanner, según el comando udevadm que hemos ejecutado antes) deben tener permisos lectura y escritura para el grupo &#8220;scanner&#8221;. Adicionalmente, se creará un enlace simbólico &#8220;/dev/scanner&#8221; apuntando al dispositivo.</p>
<p>A continuación, crearemos el grupo &#8220;scanner&#8221; y añadiremos todos los usuarios que queremos que utilicen este dispositivo:</p>
<pre>
groupadd scanner
adduser miusuario scanner
</pre>
<p>En este punto, ya podemos reiniciar el equipo o recargar el driver del scanner:</p>
<pre>
rmmod sym53c8xx
modprobe sym53c8xx
</pre>
<p>Si ha funcionado, nuestro dispositivo tendrá los siguientes permisos:</p>
<pre>
$ ls -la /dev/sg3
crw-rw----+ 1 root scanner 21, 2 2009-05-24 14:56 /dev/sg3
</pre>
<p>Finalmente podremos escanear utilizando &#8220;Aplicaciones -> Gráficos -> Programa de escaneo de imágenes <a href="http://www.xsane.org/">XSane</a>&#8221; o bien directamente desde <a href="http://www.gimp.org/">Gimp</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.marblestation.com/?feed=rss2&amp;p=888</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Sintonizador TDT Hauppauge WinTV Nova T500 PCI en Ubuntu GNU/Linux</title>
		<link>http://www.marblestation.com/?p=884</link>
		<comments>http://www.marblestation.com/?p=884#comments</comments>
		<pubDate>Sun, 24 May 2009 15:08:23 +0000</pubDate>
		<dc:creator>marble</dc:creator>
				<category><![CDATA[Castellano]]></category>

		<guid isPermaLink="false">http://www.marblestation.com/?p=884</guid>
		<description><![CDATA[Recientemente he cambiado mi equipo de sobremesa y uno de los nuevos elementos que he incorporado ha sido la sintonizadora TDT de Hauppauge WinTV Nova T500. Como siempre hago con todo el hardware que compro, la elección estuvo condicionada a que funcionase correctamente en GNU/Linux  
Para hacerla funciona en Ubuntu, lo primero que tendremos [...]]]></description>
			<content:encoded><![CDATA[<p>Recientemente he cambiado mi equipo de sobremesa y uno de los nuevos elementos que he incorporado ha sido la <a href="http://www.mythtv.org/wiki/Hauppauge_WinTV_Nova-T_500_PCI">sintonizadora TDT de Hauppauge WinTV Nova T500</a>. Como siempre hago con todo el hardware que compro, la elección estuvo condicionada a que funcionase correctamente en GNU/Linux <img src='http://www.marblestation.com/wp-includes/images/smilies/icon_biggrin.gif' alt=':-D' class='wp-smiley' /> </p>
<p>Para hacerla funciona en Ubuntu, lo primero que tendremos que hacer es descargar el correspondiente firmware:<br />
<span id="more-884"></span></p>
<pre>
cd /lib/firmware/
sudo wget http://www.wi-bw.tfh-wildau.de/~pboettch/home/files/dvb-usb-dib0700-1.20.fw
</pre>
<p>Añadimos las opciones propias de la tarjeta editando &#8220;/etc/modprobe.d/options.conf&#8221;:</p>
<pre>
#options bttv tuner=0 radio=0 pll=1 card=37 # Antigua sintonizadora PreviewPixel
options dvb-usb-dib0700 force_lna_activation=1
</pre>
<p>En este punto ya podemos reiniciar nuestro PC para que la tarjeta sea detectada correctamente. Podemos comprobar la correcta instalación mediante el comando &#8220;lsusb&#8221;:</p>
<pre>
$ lsusb
Bus 003 Device 002: ID 2040:8400 Hauppauge
</pre>
<p>A continuación vamos a generar el listado de canales disponibles para que podamos visualizarlos desde el reproductor VLC:</p>
<pre>
sudo apt-get install dvb-utils
scan /usr/share/dvb/dvb-t/es-Collserola | tee channels.conf
sudo mv channels.conf /etc/
</pre>
<p>Cabe destacar que en mi caso utilizo como &#8220;es-Collserola&#8221; como fichero base dada mi cercania a Barcelona, pero según la situación geográfica podemos utilizar otros modelos que encontraremos en el directorio &#8220;/usr/share/dvb/dvb-t/&#8221;.</p>
<p>Finalmente, para poder sintonizar la TV podemos utilizar VLC:</p>
<pre>
apt-get install vlc vlc-plugin-pulse
vlc /etc/channels.conf
</pre>
<p>A través de la lista de reproducción podremos navegar entre los diferentes canales.</p>
<p>Tenemos a nuestra disposición también programas más complejos que nos permitiran realizar grabaciones y otras opciones más avanzadas (típicas de un media center) como <a href="http://www.mythtv.org/">MythTV</a> y <a href="http://freevo.sourceforge.net/">Freevo</a> (este último no he conseguido hacerlo funcionar). Personalmente esperaba que fuesen más cómodos de utilizar, para un PC de escritorio es mucho más rápido de utilizar VLC si lo único que queremos es visualizar la programación actual.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.marblestation.com/?feed=rss2&amp;p=884</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Entrepreneurs can change the world</title>
		<link>http://www.marblestation.com/?p=880</link>
		<comments>http://www.marblestation.com/?p=880#comments</comments>
		<pubDate>Sun, 24 May 2009 14:48:29 +0000</pubDate>
		<dc:creator>marble</dc:creator>
				<category><![CDATA[Castellano]]></category>

		<guid isPermaLink="false">http://www.marblestation.com/?p=880</guid>
		<description><![CDATA[

Molt bo Tomàs!

]]></description>
			<content:encoded><![CDATA[<p><center><br />
<object width="560" height="340"><param name="movie" value="http://www.youtube.com/v/T6MhAwQ64c0&#038;hl=es&#038;fs=1"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/T6MhAwQ64c0&#038;hl=es&#038;fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="560" height="340"></embed></object><br />
<a href="http://lotomas.net/2009/05/22/entrepreneurs-can-change-the-world/">Molt bo Tomàs!</a><br />
</center></p>
]]></content:encoded>
			<wfw:commentRss>http://www.marblestation.com/?feed=rss2&amp;p=880</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Gestión centralizada de usuarios con OpenLDAP</title>
		<link>http://www.marblestation.com/?p=735</link>
		<comments>http://www.marblestation.com/?p=735#comments</comments>
		<pubDate>Sat, 23 May 2009 15:59:22 +0000</pubDate>
		<dc:creator>marble</dc:creator>
				<category><![CDATA[Castellano]]></category>

		<guid isPermaLink="false">http://www.marblestation.com/blog/?p=735</guid>
		<description><![CDATA[En uno de los últimos artículos hablábamos de cómo podemos hacer que nuestra Ubuntu sea más segura siguiendo las buenas prácticas reconocidas por los estándares internacionales. Si bien en ese mismo texto explicábamos como gestionar los usuarios locales, no valoramos cómo realizar dicha gestión cuando disponemos de una red con más de un servidor.
Con el [...]]]></description>
			<content:encoded><![CDATA[<p>En uno de los últimos artículos hablábamos de <a href="http://www.marblestation.com/blog/?p=674">cómo podemos hacer que nuestra Ubuntu sea más segura</a> siguiendo las buenas prácticas reconocidas por los estándares internacionales. Si bien en ese mismo texto explicábamos como gestionar los usuarios locales, no valoramos cómo realizar dicha gestión cuando disponemos de una red con más de un servidor.</p>
<p>Con el objetivo de tener un mayor control sobre los usuarios definidos y una política de contraseñas homogénea, lo ideal en una red es disponer de un servicio centralizado de autenticación. Imaginaros que disponemos de una red con 20 servidores y necesitásemos dar de alta un nuevo usuario, deberíamos ejecutar las pertinentes modificaciones en los 20 diferentes entornos con el riesgo de errores e inconsistencias que ésto implica. Por otra parte, desde la perspectiva del usuario nos encontramos con 20 contraseñas que no tienen porque estar sincronizadas, diferentes políticas, etc&#8230; al final es más que probable que el usuario utilice contraseñas débiles o que las anote en un postit pegado al monitor.</p>
<p>Por esos motivos, desde el punto de vista de la seguridad, es recomendable disponer de un servicio centralizado de autenticación. Históricamente en el mundo Unix se ha utilizado <a href="http://es.wikipedia.org/wiki/Network_Information_Service">NIS (Network Information Service)</a>, pero actualmente ya se encuentra en desuso y se recomienda <a href="http://es.wikipedia.org/wiki/LDAP">LDAP</a> por tratarse de un sistema más moderno y seguro.</p>
<p>Entre las implementaciones de LDAP más conocidas tenemos el <a href="http://en.wikipedia.org/wiki/Active_Directory">Directorio Activo</a> de Windows y <a href="http://en.wikipedia.org/wiki/OpenLDAP">OpenLDAP</a> para sistemas Linux/Unix (también puede integrarse con clientes Windows). Veamos como podemos montar un servicio centralizado de autenticación con OpenLDAP que cumpla los siguientes requisitos:</p>
<ul>
<li>Autenticación contra un único punto centralizado de la red.</li>
<li>Conexiones cifradas con TLS.</li>
<li>Identificación de estaciones mediante certificados digitales (únicamente podrán conectarse al servidor los clientes que dispongan de un certificado creado por nosotros y viceversa)</li>
<li>Política de contraseñas homogénea y robusta.</li>
<li>Los usuarios definidos en OpenLDAP dispondrán de campos donde se especificará a que máquinas tienen acceso. La autorización a que servicios de cada máquina se delegará a cada servidor para no perder flexibilidad.</li>
<li>Cuando el usuario se autentica por primera vez en un sistema, se almacenan sus credenciales en una cache local, de forma que si el servidor de LDAP cae temporalmente, el usuario puede seguir conectándose.</li>
</ul>
<p><span id="more-735"></span></p>
<h3>Entidad certificadora SSL</h3>
<p>Cómo comentabamos en la introducción, vamos a configurar LDAP para que se realicen conexiones cifradas. Para ésto tenemos la opción de generar un certificado SSL auto-firmado:</p>
<pre>
mkdir /etc/ldap/ssl
cd /etc/ldap/ssl
openssl req -newkey rsa:1024 -x509 -nodes -out server.pem -keyout server.pem -days 3650
</pre>
<p>Con este certificado únicamente podemos cifrar las conexiones pero no identificar los clientes o el servidor. Por tanto, cualquiera ordenador de la red puede conectarse al servidor sin que éste pueda verificar si se trata de un cliente autorizado, o a la inversa, los clientes no pueden verificar que se estan conectando al servidor autorizado y por ejemplo podrían enviar información confidencial (p.ej. contraseñas).</p>
<p>Para evitar esa situación, la configuración más segura consiste en crear nuestra propia <a href="http://es.wikipedia.org/wiki/Autoridad_de_certificaci%C3%B3n">Autoridad Certificadora</a> (CA) y emitir tantos certificados como necesitamos (1 por cliente + el servidor) firmados por la misma. Así podremos especificar que el servidor y el cliente solo acepten conexiones con certificados firmados por nuestra Autoridad Certificadora:</p>
<pre>
mkdir /etc/ssl/marblestationCA
mkdir /etc/ssl/marblestationCA/certs
mkdir /etc/ssl/marblestationCA/private

echo "01" > /etc/ssl/marblestationCA/serial
touch /etc/ssl/marblestationCA/index.txt
</pre>
<p>Creamos &#8220;/etc/ssl/marblestationCA/caconfig.cnf&#8221;:</p>
<pre>
# My sample caconfig.cnf file.
#
# Default configuration to use when one is not provided on the command line.
#
[ ca ]
default_ca      = local_ca
#
#
# Default location of directories and files needed to generate certificates.
#
[ local_ca ]
dir             = /etc/ssl/marblestationCA
certificate     = $dir/cacert.pem
database        = $dir/index.txt
new_certs_dir   = $dir/certs
private_key     = $dir/private/cakey.pem
serial          = $dir/serial

#
#
# Default expiration and encryption policies for certificates.
#
default_crl_days        = 3650
default_days            = 1825
default_md              = md5
#
policy          = local_ca_policy
x509_extensions = local_ca_extensions
#
#
# Default policy to use when generating server certificates.  The following
# fields must be defined in the server certificate.
#
[ local_ca_policy ]
commonName              = supplied
stateOrProvinceName     = supplied
countryName             = supplied
emailAddress            = supplied
organizationName        = supplied
#
#
# x509 extensions to use when generating server certificates.
#
[ local_ca_extensions ]
#subjectAltName          = DNS:host.ejemplo.com,DNS:xenhost.ejemplo.com
basicConstraints        = CA:false
#nsCertType              = server
#
#
# The default root certificate generation policy.
#
[ req ]
default_bits    = 2048
default_keyfile = /etc/ssl/marblestationCA/private/cakey.pem
default_md      = md5
#
prompt                  = no
distinguished_name      = root_ca_distinguished_name
x509_extensions         = root_ca_extensions
#
#
# Root Certificate Authority distinguished name.  Change these fields to match
# your local environment!
#
[ root_ca_distinguished_name ]
commonName              = Marble Station Root Certificate Authority
stateOrProvinceName     = Catalunya
countryName             = ES
emailAddress            = root@host.ejemplo.com
organizationName        = Marble Station
organizationalUnitName  = Host
#
[ root_ca_extensions ]
basicConstraints        = CA:true
</pre>
<p>A continuación creamos las claves que usará el CA, la contraseña que establezcamos ahora será solicitada cada vez que queramos firmar un nuevo certificado:</p>
<pre>
OPENSSL_CONF=/etc/ssl/marblestationCA/caconfig.cnf openssl req -x509 -newkey rsa:2048 -out cacert.pem -outform PEM -days 3650
</pre>
<p>Este comando generará el certificado &#8220;/etc/ssl/marblestationCA/cacert.pem&#8221; y la clave privada de CA &#8220;/etc/ssl/marblestationCA/private/cakey.pem&#8221;.</p>
<p>A continuación crearemos una clave para el servidor que ofrece el servicio LDAP y otro para un cliente, para ello creamos el fichero &#8220;/etc/ssl/marblestationCA/host-server.cnf&#8221;:</p>
<pre>
#
# desktop-server.cnf
#

[ req ]
prompt                  = no
distinguished_name      = server_distinguished_name

[ server_distinguished_name ]
commonName              = host.ejemplo.com
stateOrProvinceName     = Catalunya
countryName             = ES
emailAddress            = root@host.ejemplo.com
organizationName        = Marble Station
organizationalUnitName  = Host
</pre>
<p><b>NOTA:</b> Es muy importante tener en cuenta que el dominio que indiquemos en &#8220;commonName&#8221; debe coincidir con el dominio de la máquina que va a utilizar el certificado, de lo contrario las conexiones serán rechazadas. Por ejemplo, algo tan sencillo como un servidor con 2 dominios &#8216;uno.com&#8217; y &#8216;dos.com&#8217; apuntando a la misma IP, si el certificado se genera indicando &#8216;uno.com&#8217;, los clientes que se conecten deben hacerlo mediante ese dominio y no &#8216;dos.com&#8217;. A pesar de apuntar a la misma IP, OpenLDAP verificará el dominio utilizado.</p>
<p>Generamos la clave sin contraseña (argumento &#8220;-nodes&#8221;) dado que de lo contrario el servicio no podría arrancar de forma automática:</p>
<pre>
OPENSSL_CONF=/etc/ssl/marblestationCA/host-server.cnf openssl req -newkey rsa:1024 -keyout host-server_key.pem -keyform PEM -out host-server_req.pem -outform PEM -nodes
</pre>
<p>Utilizamos la petición de firma para el CA que acabamos de crear (&#8220;host-server_req.pem&#8221;) para generar el certificado final firmado:</p>
<pre>
OPENSSL_CONF=/etc/ssl/marblestationCA/caconfig.cnf openssl ca -in host-server_req.pem -out host-server_crt.pem
</pre>
<p>A continuación podemos repetir el proceso para generar más certificados firmados por el CA, creando un nuevo fichero de configuración (p.ej. &#8220;/etc/ssl/marblestationCA/desktop-server.cnf&#8221;) y repitiendo los pasos anteriores:</p>
<pre>
OPENSSL_CONF=/etc/ssl/marblestationCA/desktop-server.cnf openssl req -newkey rsa:1024 -keyout desktop-server_key.pem -keyform PEM -out desktop-server_req.pem -outform PEM -nodes
OPENSSL_CONF=/etc/ssl/marblestationCA/caconfig.cnf openssl ca -in desktop-server_req.pem -out desktop-server_crt.pem
</pre>
<h3>Servidor OpenLDAP</h3>
<p>En el apartado anterior hemos preparado los certificados que vamos a utilizar, ahora ha llegado la hora de instalar el servidor OpenLDAP:</p>
<pre>
apt-get install slapd ldap-utils db4.2-util
apt-get install libpam-ldap
</pre>
<p>Los certificados de la anterior sección, concretamente el certificado que será utilizado por el servidor y el certificado del CA los copiaremos a su lugar correspondiente:</p>
<pre>
sudo -s
mkdir /etc/ldap/ssl/
cp /etc/ssl/marblestationCA/host-server_key.pem /etc/ldap/ssl/
cp /etc/ssl/marblestationCA/host-server_crt.pem /etc/ldap/ssl/
cp /etc/ssl/marblestationCA/cacert.pem /etc/ldap/ssl/
chown openldap:openldap /etc/ldap/ssl/*
chmod 640 /etc/ldap/ssl/*
</pre>
<p>Copiamos el esquema que nos permitirá indicar a que hosts se pueden conectar los usuarios (atributos &#8216;host&#8217;, que pueden contener el hostname de las máquinas o un &#8216;*&#8217; para permitir acceso a todas):</p>
<pre>
cp /usr/share/doc/libpam-ldap/ldapns.schema /etc/ldap/schema/
</pre>
<p>A continuación editamos la configuración del servidor &#8216;/etc/ldap/slapd.conf&#8217;:</p>
<pre>
# Schema and objectClass definitions
include         /etc/ldap/schema/core.schema
include         /etc/ldap/schema/cosine.schema
include         /etc/ldap/schema/nis.schema
include         /etc/ldap/schema/inetorgperson.schema

include         /etc/ldap/schema/misc.schema
include         /etc/ldap/schema/ppolicy.schema
include         /etc/ldap/schema/ldapns.schema

# Where the pid file is put. The init.d script
# will not stop the server if you change this.
pidfile         /var/run/slapd/slapd.pid

# List of arguments that were passed to the server
argsfile        /var/run/slapd/slapd.args

# Read slapd.conf(5) for possible values
loglevel        none

# Where the dynamically loaded modules are stored
modulepath  /usr/lib/ldap
moduleload  back_hdb
moduleload ppolicy.la

# The maximum number of entries that is returned for a search operation
sizelimit 500

# The tool-threads parameter sets the actual amount of cpu's that is used
# for indexing.
tool-threads 1

backend     hdb
database        hdb

# The base of your directory in database #1
suffix          "dc=marblestation,dc=com"

overlay ppolicy
ppolicy_default "cn=Standard,ou=Policies,dc=marblestation,dc=com"
ppolicy_use_lockout

# rootdn directive for specifying a superuser on the database. This is needed
# for syncrepl.
rootdn          "cn=admin,dc=marblestation,dc=com"

# Where the database file are physically stored for database #1
directory       "/var/lib/ldap"

index   uid eq

# For the Debian package we use 2MB as default but be sure to update this
# value if you have plenty of RAM
dbconfig set_cachesize 0 2097152 0

# Sven Hartge reported that he had to set this value incredibly high
# to get slapd running at all. See http://bugs.debian.org/303057 for more
# information.

# Number of objects that can be locked at the same time.
dbconfig set_lk_max_objects 1500
# Number of locks (both requested and granted)
dbconfig set_lk_max_locks 1500
# Number of lockers
dbconfig set_lk_max_lockers 1500

# Indexing options for database #1
index           objectClass eq

# Save the time that the entry gets modified, for database #1
lastmod         on

# Checkpoint the BerkeleyDB database periodically in case of system
# failure and to speed slapd shutdown.
checkpoint      512 30

# The userPassword by default can be changed
# by the entry owning it if they are authenticated.
# Others should not be able to see it, except the
# admin entry below
# These access lines apply to database #1 only
# #,shadowLastChange
access to attrs=userPassword
        by dn="cn=admin,dc=marblestation,dc=com" write
        by anonymous auth
        by self write
        by * none

access to attrs=shadowLastChange
  by self write
  by * read

# Ensure read access to the base for things like
# supportedSASLMechanisms.  Without this you may
# have problems with SASL not knowing what
# mechanisms are available and the like.
# Note that this is covered by the 'access to *'
# ACL below too but if you change that as people
# are wont to do you'll still need this if you
# want SASL (and possible other things) to work
# happily.
access to dn.base="" by * read

# The admin dn has full write access, everyone else
# can read everything.
access to *
        by dn="cn=admin,dc=marblestation,dc=com" write
        by * read

TLSCertificateFile /etc/ldap/ssl/host-server_crt.pem
TLSCertificateKeyFile /etc/ldap/ssl/host-server_key.pem
TLSCACertificateFile /etc/ldap/ssl/cacert.pem
TLSVerifyClient demand
</pre>
<p>En este fichero, respecto al original, se han realizado la siguientes modificaciones:</p>
<ul>
<li>Se han añadido nuevos esquemas mediante el comando &#8216;include&#8217;.</li>
<li>Se realiza la carga del módulo &#8216;ppolicy&#8217; y se establece la configuración básica.</li>
<li>Se especifica el sufijo que será utilizado para la identificación de los datos que contendrá LDAP (&#8220;dc=marblestation,dc=com&#8221;) </li>
<li>Se establece el usuario administrador mediante el comando &#8216;rootdn&#8217; (teniendo en cuenta el mismo sufijo que hemos especificado)</li>
<li>Se configuran los certificados TLS para que estos sean requeridos y validados.</li>
</ul>
<p>Por otra parte, en el fichero &#8216;/etc/default/slapd&#8217; activaremos el servicio SSL y Unix sockets:</p>
<pre>
SLAPD_SERVICES="ldaps:/// ldapi:///"
</pre>
<p>Con esto ya podemos reiniciar nuestro servidor OpenLDAP:</p>
<pre>
/etc/init.d/slapd restart
</pre>
<p>Ahora nos falta definir la estructura base de los datos internos.</p>
<h3>Estructura del directorio</h3>
<p>La información en LDAP se almacena mediante objetos que son construidos a partir de clases definidas en los esquemas (éstos se cargan automáticamente en base a las &#8216;includes&#8217; del fichero de configuración de slapd). Veamos una definición de ejemplo:</p>
<pre>
dn: cn=admin,dc=marblestation,dc=com
objectClass: organizationalRole
objectClass: simpleSecurityObject
cn: admin
description: LDAP administrator
userPassword: {SSHA}HHWw45HYVamEIUFHp1emGejTkbY1bntB
</pre>
<p>Elementos de la definición anterior:</p>
<ul>
<li>En primer lugar tenemos el nombre unívoco (Distinguished Name) del objeto: &#8220;cn=admin,dc=marblestation,dc=com&#8221;. Siempre acompañado del sufijo que hemos especificado en la configuración (en este caso &#8220;dc=marblestation,dc=com&#8221;).</li>
<li>El objeto tendrá los atributos de las clases &#8216;organizationalRole&#8217; y &#8217;simpleSecurityObject&#8217;. Estas clases se encuentran definidos en los esquemas &#8216;/etc/ldap/schema/&#8217; que son cargados por LDAP al iniciarse. Un objeto puede estar compuesto por tantas clases auxiliares (p.ej. simpleSecurityObject) y abstractas (p.ej. top) como se requiera pero solo puede haber una de tipo estructural (organizationalRole en este caso).</li>
<li>Finalmente se listan los atributos, en este caso &#8216;cn&#8217;, &#8216;description&#8217; y &#8216;userPassword&#8217;.</li>
</ul>
<p>Todos los objetos en LDAP siguen siempre esa estructura, la cual dista bastante de las típicas bases de datos relacionales (SQL). Otra diferencia importante respecto a esas BBDD es que LDAP está optimizado para realizar consultas de lectura muy rápidas, por eso LDAP se utiliza en entornos que utilizan datos que no van a ser modificados frecuentemente (a diferencia de una BBDD relacional como MySQL).</p>
<p>Pasemos a construir la estructura básica de nuestro servidor LDAP, nos situamos en un directorio temporal de trabajo y creamos el fichero &#8217;structure.ldif&#8217;:</p>
<pre>
##### Raiz
dn: dc=marblestation,dc=com
objectClass: dcObject
objectClass: organizationalUnit
dc: marblestation
ou: marblestation Dot Com

##### Administrador de LDAP
dn: cn=admin,dc=marblestation,dc=com
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: admin
description: LDAP administrator
userPassword: {SSHA}HHWw45HYVamEIUFHp1emGejTkbY1bntB
## Password genered with slappasswd

##### Usuarios
dn: ou=People,dc=marblestation,dc=com
objectClass: organizationalUnit
ou: people

##### Grupos
dn: ou=Group,dc=marblestation,dc=com
objectClass: organizationalUnit
ou: group

##### Politicas de contraseñas
dn: ou=Policies,dc=marblestation,dc=com
objectClass: organizationalUnit
ou: policies
</pre>
<p>En ese fichero hemos definido la raiz donde colgarán todos los datos, el administrador del sistema LDAP y unidades organizativas donde añadiremos los usuarios, los grupos y las políticas de contraseña. </p>
<p>Cabe destacar que todas las contraseñas que necesitemos para definir la estructura las generaremos mediante el comando &#8217;slappasswd&#8217; (por ejemplo, la del usuario administrador anterior):</p>
<pre>
$ slappasswd
New password:
Re-enter password:
{SSHA}d2BamRTgBuhC6SxC0vFGWol31ki8iq5m
</pre>
<p>Continuemos con el contenido del servidor LDAP. Añadiremos una política de contraseñas que definiremos en el fichero &#8216;policy.ldif&#8217;:</p>
<pre>
##### Política estándard
dn: cn=Standard,ou=Policies,dc=marblestation,dc=com
objectClass: top
objectClass: device
objectClass: pwdPolicy
cn: Standard
# Field were password is stored:
pwdAttribute: userPassword
#### Expiration rules
# Number of seconds that must elapse between modifications allowed to  the  password:
# 1 day
pwdMinAge: 86400
# 60 days
pwdMaxAge: 5184000
# 7 days
pwdExpireWarning: 604800
# if its value is zero (0), users  with  expired  passwords will not be allowed to authenticate to the directory.
pwdGraceAuthnLimit: 0
# User must change its password after an admin has set it
pwdMustChange: TRUE
# Users can change their password
pwdAllowUserChange: TRUE
# It is needed the old password to set a new one
# NOTA: Si lo activamos no podremos cambiar la contraseña mediante pam_ldap
pwdSafeModify: FALSE
##### Password quality
# Maximum number of used passwords that will be stored in the pwdHistory attribute:
pwdInHistory: 12
# If its value is one (1), the server will check  the  syntax,  and  if  the
# server  is  unable  to  check  the syntax, whether due to a client-side
# hashed password or some other reason, it will be accepted. If its value
# is  two  (2),  the  server  will check the syntax, and if the server is
# unable to check the syntax it will return an error refusing  the  password.
pwdCheckQuality: 2
# Minimum  number  of  characters
pwdMinLength: 8
##### Automatic locks
# Lock user accounts after 5 failed authentications
pwdMaxFailure: 5
pwdLockout: TRUE
# 10 minutes
pwdLockoutDuration: 600
# if its value is zero (0), the failure counter will only be reset by a successful authentication
pwdFailureCountInterval: 0
</pre>
<p>Ésta política será la que aplicará a todos los usuarios (excepto al administrador LDAP) y el propio fichero es auto-explicativo.</p>
<p>Vamos a crear un usuario de prueba en el fichero &#8216;users.ldif&#8217;:</p>
<pre>
dn: uid=marble,ou=people,dc=marblestation,dc=com
objectClass: account
objectClass: posixAccount
objectClass: top
objectClass: shadowAccount
objectClass: inetLocalMailRecipient
objectClass: hostObject
objectClass: authorizedServiceObject
#objectClass: kerberosSecurityObject
#######################################
### Posix Account
uid: marble
cn: Sergi Blanco Cuaresma
gecos: Sergi Blanco Cuaresma
uidNumber: 1000
gidNumber: 1000
loginShell: /bin/bash
homeDirectory: /home/marble
#######################################
### Password
userPassword: {SSHA}PFIJb4fTH4klVKd5nE4J0WDUs3Rtmxtd
pwdReset: TRUE
#pwdPolicySubEntry: cn=Standard,ou=Policies,dc=marblestation,dc=com
#pwdPolicySubEntry: cn=No Policy, ou=Policies, dc=example, dc=com
## Discarted
#shadowExpire: -1
#shadowFlag: 0
#shadowMin: 1
shadowWarning: 7
shadowMax: 60
shadowLastChange: 0
#shadowMax: 99999
#shadowLastChange: 14156
#######################################
### Kerberos
#krbname: marble@EJEMPLO.COM
#######################################
### Authorization (e.g. host: desktop, authorizedService: sshd)
host: *
authorizedService: *
### Mail
mailRoutingAddress: marble@host.ejemplo.com
mailHost: host.ejemplo.com
</pre>
<p>Ésta sera la definición habitual de los usuarios de los sistemas, la mayoría de atributos corresponden con la información que habitualmente se almacena en sistemas Unix. Adicionalmente, tenemos otros atributos como &#8216;host&#8217;, que define a que máquinas podrá conectarse (el &#8216;*&#8217; significa &#8220;a todas&#8221;, si quisiéramos especificar máquinas tendríamos que repetir el atributo tantas veces como máquinas queramos especificar).</p>
<p>Cabe destacar que utilizaremos los atributos shadow para replicar la política global que hemos establecido con &#8216;ppolicy&#8217;. Si bien podríamos ignorarlos, no nos cuesta nada indicar la misma política de contraseña para asegurarnos que se cumple bajo cualquier circunstancia (p.ej. si tenemos conexiones SSH con autenticación por claves RSA/DSA, PAM únicamente comprueba los campos shadow y por tanto &#8216;ppolicy&#8217; no tiene efecto hasta que el usuario no realiza una conexión utilizando su clave normal).</p>
<p>Finalmente nos falta definir los grupos del sistema, añadamos un par de ejemplo en un fichero &#8216;groups.ldif&#8217;:</p>
<pre>
dn: cn=marble,ou=group,dc=marblestation,dc=com
objectClass: posixGroup
cn: marble
gidNumber: 1000

dn: cn=users,ou=group,dc=marblestation,dc=com
objectClass: posixGroup
cn: users
memberUid: marble
gidNumber: 100
</pre>
<p>Ahora que ya tenemos todos los ficheros con la estructura y los datos iniciales, ha llegado el momento de cargarlos en el servidor. Para ello borraremos todos los datos actuales de LDAP (no hemos introducido nada todavia, por tanto no debería haber nada de valor) y cargamos la información:</p>
<pre>
sudo /etc/init.d/slapd stop
sudo rm -rf /var/lib/ldap/*
sudo slapadd -l structure.ldif
sudo slapadd -l policy.ldif
sudo slapadd -l users.ldif
sudo slapadd -l groups.ldif
sudo chown -R openldap:openldap /var/lib/ldap
sudo /etc/init.d/slapd start
</pre>
<p>Si todo ha ido bien, ya tenemos nuestro servidor LDAP en marcha con la estructura base y un usuario de prueba.</p>
<h3>Consultas locales a OpenLDAP</h3>
<p>Para poder hacer consultas desde el propio servidor donde hemos instalado LDAP editamos &#8216;/etc/ldap/ldap.conf&#8217;:</p>
<pre>
BASE    dc=marblestation,dc=com
URI ldapi:///
</pre>
<p>De esta forma los comandos &#8216;ldap&#8217; se conectaran al servidor utilizando <a href="http://en.wikipedia.org/wiki/Unix_domain_sockets">Unix sockets</a> y no necesitaremos configurar TLS dado que los datos no viajan por ninguna red.</p>
<p>Podemos probar a realizar una consulta conectando como el administrador de LDAP (nos solicitará la contraseña que le hayamos asignado en la definición del mismo) y preguntando sobre los objetos con el atributo &#8216;uid=marble&#8217;:</p>
<pre>
ldapsearch -x -D "cn=admin,dc=marblestation,dc=com" -W uid=marble
</pre>
<p>Si queremos evitar tener que escribir siempre el nombre del administrador, podemos crear el archivo &#8216;~/.ldaprc&#8217;:</p>
<pre>
BASE    dc=marblestation,dc=com
URI ldapi:///
BINDDN  cn=admin,dc=marblestation,dc=com
</pre>
<p>Así simplemente bastará con ejecutar:</p>
<pre>
ldapsearch -x -W uid=marble
</pre>
<h3>Administración LDAP y gestión de usuarios</h3>
<h4>Comandos LDAP</h4>
<p>OpenLDAP proporciona diversos comandos para la administración del servicio:</p>
<ul>
ldapdelete: Borra entradas.<br />
ldapmodrdn: Modifica RDN (Relative Distinguised Names), por ejemplo permite mover &#8220;uid=marble,<b>ou=people</b>,dc=marblestation,dc=com&#8221; a &#8220;uid=marble,<b>ou=gente</b>,dc=marblestation,dc=com&#8221;<br />
ldapsearch: Realiza consultas.<br />
ldapcompare: Comparaciones.<br />
ldapmodify: Permite añadir entradas o realizar modificaciones.<br />
ldappasswd: Establece la contraseña del usuario.<br />
ldapwhoami: Indica el usuario con el que nos conectamos a LDAP.
</ul>
<p>Su uso no es sencillo y para aprender a utilizarlas lo mejor es consultar sus respectivos manuales. No obstante, disponemos de otras interfícies que nos facilitaran la gestión de LDAP.</p>
<h4>phpLDAPadmin</h4>
<p>Para la administración general del LDAP, si tenemos ya <a href="http://www.marblestation.com/blog/?p=674#6">configurado Apache2</a>, una de las opciones más cómodas es la instalación de <a href="http://phpldapadmin.sourceforge.net">phpldapadmin</a>:</p>
<pre>
apt-get install phpldapadmin
</pre>
<p>Editamos &#8216;/etc/phpldapadmin/config.php&#8217; y establecemos los siguientes parámetros (acceso local por Unix sockets, etc.):</p>
<pre>
...
$ldapservers->SetValue($i,'server','host','ldapi://');
...
$ldapservers->SetValue($i,'server','base',array('dc=marblestation,dc=com'));
...
$ldapservers->SetValue($i,'login','dn','cn=admin,dc=marblestation,dc=com');
...
</pre>
<p>Podremos acceder a la aplicación mediante &#8216;http://localhost/phpldapadmin/&#8217; y desde allí la aplicación nos permitirá realizar consultar, modificaciones, duplicar objetos, etc.</p>
<h4>CPU &#8211; Change Passowrd Utility</h4>
<p>Si bien con phpLDAPadmin podremos realizar casi cualquier operación sobre LDAP vía web, CPU nos proporciona comandos de consola análogos a los tradicionales &#8216;useradd&#8217;, &#8216;usermod&#8217;, &#8216;userdel&#8217;, &#8216;groupadd&#8217;, etc. Ésto puede facilitar al administrador la tarea de gestión de usuarios:</p>
<pre>
apt-get install cpu
</pre>
<p>Editamos &#8216;/etc/cpu/cpu.conf&#8217; para establecer las opciones de conexión (vía local por Unix Socket), usuario administrador LDAP (no indicamos la contraseña, haremos que nos la pregunte cada vez que ejecutemos cpu) y otros parámetros:</p>
<pre>
# See cpu.conf(5) for documentation

[GLOBAL]
DEFAULT_METHOD  = ldap
CRACKLIB_DICTIONARY = /var/cache/cracklib/cracklib_dict

[LDAP]
LDAP_URI                = ldapi:///
BIND_DN                 = "cn=admin,dc=marblestation,dc=com"
BIND_PASS               = ""
USER_BASE               = "ou=People,dc=marblestation,dc=com"
GROUP_BASE              = "ou=Group,dc=marblestation,dc=com"
USER_OBJECT_CLASS       = account,posixAccount,shadowAccount,top,inetLocalMailRecipient,hostObject,authorizedServiceObject
#kerberosSecurityObject
GROUP_OBJECT_CLASS  = posixGroup,top
USER_FILTER = (objectClass=posixAccount)
GROUP_FILTER    = (objectClass=posixGroup)
USER_CN_STRING  = uid
GROUP_CN_STRING = cn
SKEL_DIR    = /etc/skel
DEFAULT_SHELL   = /bin/bash
HOME_DIRECTORY  = /home
MAX_UIDNUMBER = 10000
MIN_UIDNUMBER = 1000
MAX_GIDNUMBER = 10000
MIN_GIDNUMBER = 1000
ID_MAX_PASSES = 1000
# Whether each user should have its own group created or not
USERGROUPS = yes
# If you change usergroup set this to the default group a user should have
#USERS_GID = 100
RANDOM = "false"
PASSWORD_FILE = "/etc/passfile"
SHADOW_FILE = "/etc/shadowfile"
HASH = "clear"
SHADOWLASTCHANGE    = 11192
SHADOWMAX       = 99999
SHADOWWARING        = 7
SHADOWEXPIRE        = -1
SHADOWFLAG      = 134538308
SHADOWMIN       = -1
SHADOWINACTIVE      = -1
</pre>
<p>Adicionalmente, crearemos el fichero &#8216;/etc/cpu/attributes.ldif&#8217;:</p>
<pre>
pwdReset: TRUE
host: *
authorizedService: *
</pre>
<p>De esta forma, cuando creemos usuarios se añadirán los atributos anteriores por defecto (el usuario esta obligado a resetear la contraseña y tiene acceso a todos los sistemas). Hagamos una prueba añadiendo un nuevo usuario (la primera contraseña que nos solicita corresponde a la del administrador LDAP):</p>
<pre>
cpu -w -a /etc/cpu/attributes.ldif useradd -p test01
</pre>
<p>El anterior comando generará el usuario &#8216;test01&#8242; y el grupo &#8216;test01&#8242;.</p>
<p>Si queremos listar los usuarios definidos:</p>
<pre>
cpu -w cat
</pre>
<p>Bloqueo y desbloqueo de usuarios:</p>
<pre>
cpu -w usermod -L test01
cpu -w usermod -U test01
</pre>
<p>Borrado de usuarios:</p>
<pre>
cpu -w userdel prueba22
</pre>
<p>Para consultar el listado completo de comandos que podemos ejecutar con &#8216;cpu&#8217; podemos consultar el manual:</p>
<pre>
man cpu-ldap
</pre>
<h3>Clientes OpenLDAP</h3>
<p>A continuación vamos a configurar una máquina que se conectará contra el servidor OpenLDAP para autenticar a sus usuarios:</p>
<pre>
apt-get install libpam-ldap libnss-ldap nss-updatedb libnss-db ldap-utils libpam-ccreds
</pre>
<p>Para la conexión, necesitaremos disponer de un certificado firmado por la CA que hemos generado tal y como se especificaba al inicio del artículo. Una vez generados los certificados (clave privada, clave pública firmada y certificado CA), los copiaremos mediante sftp y los moveremos al lugar correspondiente:</p>
<pre>
sudo -s
mkdir /etc/ldap/ssl/
cp /etc/ssl/marblestationCA/desktop-server_key.pem /etc/ldap/ssl/
cp /etc/ssl/marblestationCA/desktop-server_crt.pem /etc/ldap/ssl/
cp /etc/ssl/marblestationCA/cacert.pem /etc/ldap/ssl/
chmod 644 /etc/ldap/ssl/*
chown root:root /etc/ldap/ssl/*
</pre>
<p>A continuación vamos a configurar LDAP como cliente, editamos &#8216;/etc/ldap/ldap.conf&#8217;:</p>
<pre>
BASE    dc=marblestation,dc=com
URI     ldaps://host.ejemplo.com

TLS_CACERT /etc/ldap/ssl/cacert.pem
TLS_REQCERT demmand
#TLS_REQCERT never # Useful to check if "Can't contact LDAP server" because of certificate problems
</pre>
<p>Utilizando el usuario que vayamos a utilizar para conectarnos al servidor, creamos &#8216;~/.ldaprc&#8217;:</p>
<pre>
BASE    dc=marblestation,dc=com
URI     ldaps://host.ejemplo.com
BINDDN  cn=admin,dc=marblestation,dc=com

TLS_CACERT /etc/ldap/ssl/cacert.pem
TLS_REQCERT demmand
#TLS_REQCERT never # Useful to check if "Can't contact LDAP server" because of certificate problems

#### User only (need to copy /etc/ldap/ldap.conf to ~/.ldaprc)
# Client certificate and key
# Use these, if your server requires client authentication.
TLS_CERT /etc/ldap/ssl/desktop-server_crt.pem
TLS_KEY /etc/ldap/ssl/desktop-server_key.pem
</pre>
<p>En esos dos ficheros hemos especificado:</p>
<ul>
<li>El nombre base &#8220;dc=marblestation,dc=com&#8221;.</li>
<li>El servidor al que nos vamos a conectar y el protocolo que vamos a utilizar, en este caso nos conectaremos mediante SSL al puerto 636 LDAP del servidor &#8216;host.ejemplo.com&#8217;. Es muy importante que este dominio coincida con el &#8216;commonName&#8217; especificado en el servidor al cual nos vamos a conectar, de lo contrario la conexión no se establecerá.</li>
<li>El usuario con el que vamos a realizar la conexión (corresponde al administrador).</li>
<li>Certificado privado, público firmado y CA, así como la solicitud de validación del certificado del servidor.</li>
</ul>
<p>A continuación podemos probar la conexión realizando una consulta al servidor:</p>
<pre>
ldapsearch -x -W uid=marble
</pre>
<p>Ahora que ya hemos podido comprobar que podemos conectarnos sin problemas desde el cliente, vamos a configurar el sistema para que autentique los usuarios contra LDAP.</p>
<p>Lo primero será editar el fichero &#8216;/etc/ldap.conf&#8217; para establecer los parámetros de conexión utilizados por <a href="http://es.wikipedia.org/wiki/Pluggable_Authentication_Modules">PAM</a> (sistema habitual de autenticación):</p>
<pre>
# Your LDAP server. Must be resolvable without using LDAP.
uri ldaps://host.ejemplo.com

# The distinguished name of the search base.
base dc=marblestation,dc=com

ldap_version 3

# The distinguished name to bind to the server with
# if the effective user ID is root. Password is
# stored in /etc/ldap.secret (mode 600)
# NOTA: No activar o dejará de ser efectiva la politica de contraseñas (ppolicy)
#rootbinddn cn=admin,dc=marblestation,dc=com

# Search timelimit
timelimit 5

# Bind/connect timelimit
bind_timelimit 5

# Reconnect policy: hard (default) will retry connecting to
# the software with exponential backoff, soft will fail
# immediately.
bind_policy soft

# Filter to AND with uid=%s
#pam_filter objectclass=posixAccount
#pam_filter gidNumber=1000

# check for login rights on the host
pam_check_host_attr yes
#pam_filter (&#038;(objectClass=posixAccount)(authorizedService=site-admin))
#pam_filter |(host=desktop)(host=\*)

#pam_check_service_attr yes

pam_lookup_policy yes

# Specify a minium or maximum UID number allowed
#pam_min_uid 1000
#pam_max_uid 0

# Do not hash the password at all; presume
# the directory server will do it, if
# necessary. This is the default.
#pam_password md5
pam_password clear

# OpenLDAP SSL mechanism
# start_tls mechanism uses the normal LDAP port, LDAPS typically 636
ssl start_tls
ssl on

# OpenLDAP SSL options
# Require and verify server certificate (yes/no)
tls_checkpeer yes
# tls_checkpeer no # Useful to check if "Can't contact LDAP server" because of certificate problems

# CA certificates for server certificate verification
#tls_cacertdir /etc/ssl/certs
tls_cacertfile /etc/ldap/ssl/cacert.pem

# Client certificate and key
tls_cert /etc/ldap/ssl/desktop-server_crt.pem
tls_key /etc/ldap/ssl/desktop-server_key.pem

use_sasl off
rootuse_sasl off
sasl_secprops maxssf=0
idle_timelimit 3600
nss_reconnect_tries 1
nss_reconnect_sleeptime 1
nss_reconnect_maxsleeptime 8
nss_reconnect_maxconntries 2
nss_paged_results yes
nss_base_passwd ou=people,dc=marblestation,dc=com?one
nss_base_shadow ou=people,dc=marblestation,dc=com?one
nss_base_group ou=group,dc=marblestation,dc=com?one

nss_initgroups_ignoreusers avahi,avahi-autoipd,backup,bin,chipcard,daemon,dhcp,ftp,games,gdm,gnats,haldaemon,hplip,irc,klog,landscape,libuuid,list,lp,mail,man,messagebus,news,nx,polkituser,proxy,pulse,root,snmp,sshd,sync,sys,syslog,uucp,www-data
</pre>
<p>En este fichero hemos especificado:</p>
<ul>
<li>Host al que nos conectaremos. Como siempre, es importante que coincida con el &#8216;commonName&#8217; del certificado del servidor, de lo contrario la conexión no se establecerá.</li>
<li>Opciones de conexión varias (el puerto 636 corresponde a ldaps://).</li>
<li>Configuraciones PAM:
<ul>
<li>Validación del atributo &#8216;host&#8217;. Si el usuario dispone de un atributo &#8216;host&#8217; con valor &#8216;*&#8217; o con el nombre de la máquina (debe coincidir con el resultado del comando &#8216;hostname&#8217;), entonces podrá logearse en el sistema. De lo contrario, se deniega el acceso.</li>
<li>Validación de la política de contraseñas.</li>
<li>Envío de contraseñas en claro. Este requisito es necesario para que la política de contraseñas pueda ser validada en el servidor y por otra parte, tampoco supone un riesgo de seguridad dado que la conexión será cifrada.</li>
</ul>
</li>
<li>Configuración de los certificados a utilizar.</li>
<li>Rutas donde encontrar la información de usuarios, grupos, etc.</li>
</ul>
<p>A continuación vamos a preparar el sistema para que si perdemos conectividad, podamos seguir asociando uid y gid con los nombres asignados. Para esto se copiaran todos los usuarios y grupos (solo uid/gid y nombres) en local mediante el comando:</p>
<pre>
sudo nss_updatedb ldap
</pre>
<p>Es necesario que esta actualización se haga de forma periódica mediante cron (al menos 1 vez al día) por si hay cambios en el servidor:</p>
<pre>
echo '#!/bin/sh'               | sudo tee    /etc/cron.daily/upd-local-nss-db
echo `which nss_updatedb` ldap | sudo tee -a /etc/cron.daily/upd-local-nss-db
sudo chmod +x /etc/cron.daily/upd-local-nss-db
</pre>
<p>En este punto estamos preparados para indicarle al sistema de donde debe obtener la información sobre usuarios, contraseñas y grupos, para ello editamos &#8216;/etc/nsswitch.conf&#8217; y cambiamos:</p>
<pre>
#passwd:         compat
#group:          compat
#shadow:         compat
</pre>
<p>Por:</p>
<pre>
passwd:         files ldap [NOTFOUND=return] db
group:          files ldap [NOTFOUND=return] db
shadow:     files ldap
</pre>
<p>En estas líneas estamos indicando que el sistema debe buscar la información de usuarios y grupos primero en los archivos locales (/etc/passwd y /etc/group) y después en LDAP, pero en caso de que este último falle entonces debe consultar la copia local que hemos realizado con &#8216;nss_updatedb&#8217;. En el caso de las contraseñas, únicamente consultará el fichero local (&#8216;/etc/shadow&#8217;) y el servidor (el cacheo de credenciales lo realizaremos por otra vía).</p>
<p>Con esta configuración tendremos máxima flexibilidad dado que podremos optar por tener usuario/grupos locales y usuarios/grupos centralizados de forma simultanea. O bien, podemos migrar todas las cuentas a LDAP y dejar en blanco los archivos locales.</p>
<p>Para validar la configuración, podemos comprobar el listado de usuarios/grupos actuales de nuestro sistema (combinará los definidos localmente con los usuarios creados en LDAP):</p>
<pre>
sudo getent passwd
sudo getent group
</pre>
<p>Finalmente nos falta configurar los archivos de autenticación PAM. </p>
<p><b>NOTA:</b> Si estamos accediendo remotamente al servidor que estamos modificando, es importante tener en cuenta que estos cambios pueden bloquearnos futuros accesos y por tanto debemos probar cada cambio que hagamos. </p>
<p>Comenzaremos editando &#8216;/etc/pam.d/common-auth&#8217; para que quede con el siguiente contenido:</p>
<pre>
auth    [success=done default=ignore]   pam_unix.so nullok_secure try_first_pass
# If LDAP is unavailable, go to next line.  If authentication via LDAP is successful, skip 1 line.
# If LDAP is available, but authentication is NOT successful, skip 2 lines.
auth    [authinfo_unavail=ignore success=1 default=2] pam_ldap.so use_first_pass
auth    [default=done]  pam_ccreds.so action=validate use_first_pass
auth    [default=done]  pam_ccreds.so action=store
auth    [default=bad]   pam_ccreds.so action=update
</pre>
<p>En este fichero hemos indicado que primero debe intentar autenticar los usuarios utilizando la información local, de lo contrario trata de autenticar contra el servidor LDAP (utilizando la configuración &#8216;/etc/ldap.conf&#8217; que ya hemos preparado). Si este último falla, comprobará si las credenciales se encuentran cacheadas en local e intentará autenticarlo (antepenúltima línea).</p>
<p>Por otra parte, cada vez que se realice una autenticación exitosa contra LDAP, se ejecutará la penúltima línea y se guardarán las credenciales en local (concretamente en /var/cache/.security.db). En caso que la cuenta haya sido bloqueada/eliminada de LDAP, se ejecutará la última línea con la cual se borraran las credenciales cacheadas del usuario.</p>
<p>Editemos ahora &#8216;/etc/pam.d/common-account&#8217; para que quede con el siguiente contenido:</p>
<pre>
account     [user_unknown=ignore authinfo_unavail=ignore default=done] pam_ldap.so
account     [user_unknown=ignore authinfo_unavail=ignore default=done] pam_unix.so
account     required       pam_permit.so
</pre>
<p>Editamos &#8216;/etc/pam.d/common-session&#8217; y lo dejamos así:</p>
<pre>
session    required     pam_limits.so
#session    required     pam_mkhomedir.so skel=/etc/skel/
session    required     pam_unix.so
session    optional     pam_ldap.so
</pre>
<p>Editamos &#8216;/etc/pam.d/common-password&#8217; para que contenga:</p>
<pre>
password   required   pam_ldap.so ignore_unknown_user
password   optional   pam_unix.so shadow md5 try_first_pass
</pre>
<p>A continuación podemos probar a autenticarnos en el sistema (login normal, ssh o &#8217;su &#8211; usuario&#8217;) utilizando usuarios locales y usuarios definidos en LDAP (p.ej. el que hemos creado de prueba).</p>
<p>Cuando conectemos con el usuario de LDAP, las credenciales han debido ser cacheadas y podemos validarlo mediante:</p>
<pre>
sudo cc_dump
  Credential Type  User             Service  Cached Credentials
  ----------------------------------------------------------------------------------
  Salted SHA1      fred             any     4a985b233701cf106ed450a0168fa8e0aa86ef5d
</pre>
<p>En caso de que queramos borrar manualmente alguna credencial cacheada, podemos ejecutar:</p>
<pre>
sudo cc_test -update any usuario -
</pre>
<p>Con esto ya tenemos montado el sistema de autenticación centralizado cliente-servidor <img src='http://www.marblestation.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.marblestation.com/?feed=rss2&amp;p=735</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Awstats con autenticación y geolocalización de IPs</title>
		<link>http://www.marblestation.com/?p=869</link>
		<comments>http://www.marblestation.com/?p=869#comments</comments>
		<pubDate>Sat, 23 May 2009 14:38:52 +0000</pubDate>
		<dc:creator>marble</dc:creator>
				<category><![CDATA[Castellano]]></category>

		<guid isPermaLink="false">http://www.marblestation.com/?p=869</guid>
		<description><![CDATA[En el artículo sobre seguridad técnica en un sistema Ubuntu hablé por primera vez de awstat como herramienta para monitorizar los accesos a páginas web. Veamos como añadir restricciones de acceso y geolocalización de IPs.

La configuración base la podemos mejorar añadiendo autenticación, para esto tendremos que tener activos varios módulos de nuestro servidor apache:

a2enmod auth_basic
a2enmod [...]]]></description>
			<content:encoded><![CDATA[<p>En el artículo sobre <a href="http://www.marblestation.com/?p=674">seguridad técnica en un sistema Ubuntu</a> hablé por primera vez de <a href="http://awstats.sourceforge.net/">awstat</a> como herramienta para monitorizar los accesos a páginas web. Veamos como añadir restricciones de acceso y geolocalización de IPs.<br />
<span id="more-869"></span></p>
<p>La configuración base la podemos mejorar añadiendo autenticación, para esto tendremos que tener activos varios módulos de nuestro servidor apache:</p>
<pre>
a2enmod auth_basic
a2enmod authn_file
a2enmod authz_user
</pre>
<p>Editamos el fichero donde hayamos definido el dominio de nuestra página web, por ejemplo &#8220;/etc/apache2/sites-enabled/000-ejemplo.com&#8221; y debajo de:</p>
<pre>
ScriptAlias /cgi-bin/awstats.pl /usr/lib/cgi-bin/awstats.pl
</pre>
<p>Añadimos:</p>
<pre>
    &#60;Directory /usr/lib/cgi-bin/awstats.pl>
        AllowOverride All
        Options FollowSymLinks
        Order allow,deny
        allow from all

        AuthName "Acceso restringido a Estadísticas"
        AuthType basic
        AuthUserFile /etc/awstats/htpasswd.ejemplo.com
        require valid-user
    &#60;/Directory>
</pre>
<p>De esta forma estamos indicando a Apache que queremos autenticar los usuarios que accedan a &#8220;awstats.pl&#8221; y que los usuarios/contraseñas los tiene que comprobar en el fichero &#8220;/etc/awstats/htpasswd.ejemplo.com&#8221;. Así que necesitamos crear este último fichero con los usuarios que necesitemos:</p>
<pre>
htpasswd -cm /etc/awstats/htpasswd.ejemplo.com usuario1
htpasswd -m /etc/awstats/htpasswd.ejemplo.com usuario2
</pre>
<p>Para mayor seguridad, en la configuración de awstats (p.ej. &#8216;/etc/awstats/awstats.ejemplo.com.conf&#8217;) indicamos que únicamente queremos que awstats se muestre a usuarios autenticados:</p>
<pre>
AllowAccessFromWebToAuthenticatedUsersOnly=1
</pre>
<p>Reiniciamos apache y ya tenemos restringido el acceso a awstats:</p>
<pre>
/etc/init.d/apache reload
</pre>
<p>Por otra parte, si queremos añadir geolocalización de IPs a awstats:</p>
<pre>
sudo -s
apt-get install liburi-perl libgeo-ip-perl
mkdir /usr/local/share/GeoIP
cd /usr/local/share/GeoIP
wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz
wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
wget http://geolite.maxmind.com/download/geoip/database/asnum/GeoIPASNum.dat.gz
gzip -d *
</pre>
<p>Y añadimos a la configuración de awstats  (p.ej. &#8216;/etc/awstats/awstats.ejemplo.com.conf&#8217;):</p>
<pre>
LoadPlugin="geoip GEOIP_STANDARD /usr/local/share/GeoIP/GeoIP.dat"
LoadPlugin="geoip_city_maxmind GEOIP_STANDARD /usr/local/share/GeoIP/GeoLiteCity.dat"
LoadPlugin="geoip_org_maxmind GEOIP_STANDARD /usr/local/share/GeoIP/GeoIPASNum.dat"
</pre>
<p>Listo una configuración modelo de awstats por si resulta de utilidad, donde también se incluyen secciones extra especialmente pensadas por si la página en cuestión es un wordpress:</p>
<pre>
LogFile="/var/log/apache2/vhosts/ejemplo.com.access.log"
LogFormat=1
DNSLookup=1
DirData="/var/lib/awstats/ejemplo.com/"
DirCgi="/cgi-bin"
DirIcons="/icon"
SiteDomain="ejemplo.com"
HostAliases="www.ejemplo.com" # Separated by spaces
AllowToUpdateStatsFromBrowser=1
AllowFullYearView=3
AllowAccessFromWebToAuthenticatedUsersOnly=1
SkipFiles="REGEX[^\/wp-admin] REGEX[^\/wp-includes\/wlwmanifest.xml] REGEX[^\/cgi-bin\/awstats.pl] REGEX[^\/icons] REGEX[^\/w00tw00t\.at\.ISC\.SANS\.DFind]"
SkipHosts="REGEX[^192\.168\.]"
NotPageList="css js class gif jpg jpeg png bmp ico swf" # what file extensions will not be counted as Page Views or Downloads
#LevelForWormsDetection=2 # Full detection (decreases speed by 15%
#ShowWormsStats=HBL

# "/js/awstats_misc_tracker.js" needs to be added to webpage
# More info: http://awstats.sourceforge.net/docs/awstats_config.html#MiscTrackerUrl
MiscTrackerUrl="/js/awstats_misc_tracker.js"
ShowScreenSizeStats=1
ShowMiscStats=1

# Show domains/country chart
# # Context: Web, Streaming, Mail, Ftp
# # Default: PHB, Possible column codes: PHB
ShowDomainsStats=UVPHB

LoadPlugin="tooltips" # Help
LoadPlugin="decodeutfkeys" # makes it possible to show keywords and keyphrases correctly using national characters
LoadPlugin="geoip GEOIP_STANDARD /usr/local/share/GeoIP/GeoIP.dat"
LoadPlugin="geoip_city_maxmind GEOIP_STANDARD /usr/local/share/GeoIP/GeoLiteCity.dat"
LoadPlugin="geoip_org_maxmind GEOIP_STANDARD /usr/local/share/GeoIP/GeoIPASNum.dat"

ExtraSectionName1="Wordpress entries"
# Code 304: Not modified
# Code 200: OK
ExtraSectionCodeFilter1="200 304"
# http://domain/?p=100
ExtraSectionCondition1="URL,\/"
ExtraSectionFirstColumnTitle1="Entry ID"
ExtraSectionFirstColumnValues1="QUERY_STRING,p=([^&#038;]+)"
ExtraSectionFirstColumnFormat1="<a href='/?p=%s' target=new>www.ejemplo.com/?p=%s</a>"
##
## U = Unique visitors
## V = Visits
## P = Number of pages
## H = Number of hits (or mails)
## B = Bandwith (or total mail size for mail logs)
## L = Last access date
## E = Entry pages
## X = Exit pages
## C = Web compression (mod_gzip,mod_deflate)
ExtraSectionStatTypes1=UVPHBL
ExtraSectionAddAverageRow1=0
ExtraSectionAddSumRow1=1
MaxNbOfExtra1=10
MinHitExtra1=1

ExtraSectionName2="Wordpress pages"
ExtraSectionCodeFilter2="200 304"
ExtraSectionCondition2="URL,\/"
ExtraSectionFirstColumnTitle2="Page ID"
ExtraSectionFirstColumnValues2="QUERY_STRING,page_id=([^&#038;]+)"
ExtraSectionFirstColumnFormat2="<a href='/?page_id=%s' target=new>www.ejemplo.com/?page_id=%s</a>"
ExtraSectionStatTypes2=UVPHBL
ExtraSectionAddAverageRow2=0
ExtraSectionAddSumRow2=1
MaxNbOfExtra2=10
MinHitExtra2=1

ExtraSectionName3="Top downloads"
ExtraSectionCodeFilter3="200 304"
ExtraSectionCondition3="URL,(.*((\.diff)|(\.doc)|(\.pdf)|(\.rtf)|(\.sh)|(\.tgz)|(\.zip)|(\.bz2)|(\.gz)))"
ExtraSectionFirstColumnTitle3="Download"
ExtraSectionFirstColumnValues3="URL,(.*)"
ExtraSectionFirstColumnFormat3="<a href='http://%s' target='_blank'>%s</a>"
ExtraSectionStatTypes3=HBL
ExtraSectionAddAverageRow3=0
ExtraSectionAddSumRow3=1
MaxNbOfExtra3=10
MinHitExtra3=1
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.marblestation.com/?feed=rss2&amp;p=869</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
