OpenLDAP
Contenido
- 1 OpenLDAP
- 2 dbd and hdb backends comparison
- 3 Update scripts
- 4 Problemas
OpenLDAP
Main references
Other references
Introducción a LDAP en español
- http://www.linuxfocus.org/Castellano/July2000/article159.shtml
- http://ldp.ludost.net/linuxfocus/Castellano/July2000/article159.meta.html
Introducción en Ingles
- http://www.yolinux.com/TUTORIALS/LinuxTutorialLDAP.html
- http://www.developer.com/tech/article.php/2197131
- Understanding LDAP - Design and Implementation (Red Book de IBM)
- LDAP for Rocket Scientists
Procedimientos
- Setting up and configuring an LDAP server (Debian etch)
- LDAP Authentication In Linux
- Configuración de un cliente y servidor OpenLDAP para autentificación
- Instalación y configuración de OpenLDAP
- Autentificación de un cliente linux a través de LDAP
- Autenticación LDAP en GNU/Linux
- Using LDAP for name resolution
- Sistema de cuentas de correo virtuales con PostFix, OpenLDAP y Courier
Como Addressbook
- Building an Address Book with OpenLDAP
- LDAP for Address Book
- http://www.scheduleworld.com/addressbook.html
- Build an LDAP-based address book
Configuracion
Integracion Open LDAP y Samba
Replicación
Performance
- http://wiki.zimbra.com/index.php?title=OpenLDAP_Performance_Tuning_5.0
- http://wiki.zimbra.com/index.php?title=OpenLDAP_Performance_Tuning_6.0
Herramientas
- phpLDAPadmin
- GOsa - GOnicus System Administrator
- LDAP Account Manager (Debian)
- web2ldap - WWW gateway to LDAP server
- YALA - Yet Another LDAP Administrator
- LABE - Ldap Address Book Editor
- JXplorer - Originalmente de CA
- LDAP Explorer
- GQ (GTK)
Procedimiento de instalaccion de servidor OpenLDAP
Objetivos
- Conseguir una unica base de contactos.
- Sincronización con PALM y teléfono celular.
- Lista de contactos común para clientes de email con Evolution, Mozilla y Outlook.
- Replicación entre equipo base y notebook.
Instalación
apt-get install slapd ldap-utils
En la configuración del paquete use las opciones estandares.
Configuracion
geaceku:/home/admin/ldap# more addressbook.ldif dn: ou=addressbook,dc=otrasyerbas,dc=com,dc=ar objectClass: top objectClass: organizationalUnit ou: addressbook geaceku:/home/admin/ldap# ldapadd -x -D 'cn=admin,dc=otrasyerbas,dc=com,dc=ar' -f addressbook.ldif -W Enter LDAP Password: adding new entry "ou=addressbook,dc=otrasyerbas,dc=com,dc=ar"
Comandos utiles
# Ver el contenido del directorio: slapcat
Mensajes de error
geaceku:/home/admin/ldap# ldapadd -x -D 'cn=admin,dc=otrasyerbas,dc=com,dc=ar' -f directory.ldif -W Enter LDAP Password: adding new entry "dc=otrasyerbas,dc=com,dc=ar" ldapadd: update failed: dc=otrasyerbas,dc=com,dc=ar ldap_add: Insufficient access (50) geaceku:/home/admin/ldap# ldapwhoami ldap_sasl_interactive_bind_s: No such attribute (16) geaceku:/home/admin/ldap# ldapwhoami -x anonymous geaceku:/home/admin/ldap#
En sarge arrancando slapd
geacequ:/# /etc/init.d/slapd restart Stopping OpenLDAP: slapd. Starting OpenLDAP: (db4.2_recover not found), slapd.
Es un problema de dependencia de sarge, se arregla con:
apt-get install db4.2-util
Evolution
Error loading addressbook
We were unable to open this addressbook. This either means you have entered an incorrect URI, or the LDAP server is unreachable.
Aparentemente es un bug de la version slapd version 2.1.30 que solo se manifiesta con Evolution :( aparentemente la unica solicion es: upgrade/downgrade
Base de datos
La base puede estar en dos formatos
- BDB
- HDB
- ldbm?
La base de datos se instala inicialmente en /var/lib/ldap En este directorio vamos a encontrar tambien al archivo con el cual se configuran los parametros de la base: DB_CONFIG
Clientes de LDAP
El objetivo de esta parte es poder hacer un slapcat desde una máquina que no sea el servidor y funcione correctamente.
Para conseguir eso tendremos que intalar al menos los paquetes libldap2, ldap-utils.
Una vez instalados estos paquetes, editaremos el fichero /etc/ldap/ldap.conf. Este fichero es el de configuración del cliente LDAP, no lo tenemos que confundir confundir con el fichero slapd.conf, que es de la configuración del servidor.
El fichero podemos dejarlo así:
host 192.168.1.2 base dc=pinux,dc=info
De esa forma le decimos donde tiene que conectarse y el dc.
Ahora desde la máquina cliente podemos hacer uso del slapcat igual que antes. La configuración por defecto permite la lectura de varios campos por "todo el mundo", así que aunque no veremos la contraseña podremos ver otra información del usuario.
nsswitch
Para esta parte necesitaremos instalar el paquete libnss-ldap.
apt-get install libnss-ldap
Cuando trabajamos con el sistema (ls -l, p. ej.) normalmente vemos los nombres de los usuarios propietarios de los ficheros. En cambio guardado en el disco hay el "número" (UID) del usuario.
Para que los programas sepan el nombre que corresponde a los UID's (y otras cosas, como grupos, hosts, etc.) hacen unas llamadas a funciones de la librería GLIBC, y es esta quien "averigua" la relación.
Es en el fichero /etc/nsswitch.conf donde le decimos al sistema de donde averiguar el propietario sabiendo el UID. Normalmente contiene algo como:
passwd: compat group: compat shadow: compat hosts: files dns networks: files
Lo que más nos interesa es la parte de passwd, group y shadow. Ahora lo dejaremos así:
passwd: compat ldap group: compat ldap shadow: compat ldap
Por tanto cuando un programa le pide a la GLIBC "dime el nombre del usuario 1005", la GLIBC primero mira en /etc/passwd y sinó hará la consula al servidor LDAP.
Para que el nsswitch pueda hacer las consultas en el LDAP tendremos el fichero /etc/libnss-ldap.conf algo como:
host 192.168.1.2 base dc=pinux,dc=info
Es decir, la información necesaria para llegar a nuestro servidor LDAP y lanzar la consulta. Si hacemos man libnss-ldap.conf veremos las opciones que podemos ponerle (p. ej. port, ldap_versions, etc.)
Entre otras cosas, a veces necesitaremos que se haga una conexión autentificada contra el servidor. Para eso se usará la contraseña que encuentre en /etc/ldap.secret (tiene que estar con permisos 600, propietario y grupo root) Create /etc/ldap.secret with the password for rootbindn with the password on one line and then press <Enter>. There must be a blank second line. Then protect it with: chmod 0600 /etc/ldap.secret. Este password puede estar encriptado. Para hacerlo ejecutaremos slappasswd y la que nos diga la pondremos en el archivo. Por ejemplo: {SSHA}xAR4MvR0AByRx0gYCZGKeWUFAhNGZIud.
nscd
Para evitar que sea consultado el servidor LDAP cada vez que es ejecutado un comando como ls -l dentro de nuestra organización, es una buena idea configurar en nuestras estaciones de trabajo un sistema de cache para algunos datos de usuario. Mientras los datos en la cache sean lo suficiente recientes, las estaciones de trabajo utilizarán estos en vez de preguntar al servidor LDAP otra vez. El demonio servidor de cacheo de nombres (nscd) cumple exactamente esta tarea.
# apt-get install nscd
El archivo de configuración de nscd es /etc/nscd.conf.
enable-cache passwd yes positive-tive-to-live passwd 600 negative-time-to-live passwd 20 suggested-size passwd 211 check-files passwd yes
Configurando el cliente PAM
OJO ALGO MAL HAY ACA PORQUE QUEDA MAL CONFIGURADO, PIDE EL PASSWD 2 VECES, REVISAR Y CORREGIR
La idea es que el cliente se autentifique en nuestro LDAP para eso tenemos que confirgurar el PAM de cada cliente.
Para poder configurar el cliente PAM tendremos que instalar el paquete libpam-ldap.
apt-get install libpam-ldap
Hay varios programas que pueden usar (y usan por defecto) un método de autentificación "centralizado" y por módulos llamado PAM (Pluggable Authentication Modules). Eso son unas librerias que los programas pueden soportar que sirven de "interfaz" contra varios métodos de autentificación (p. ej. LDAP)
La configuración en Debian es en el directorio /etc/pam.d/ y tenemos un fichero de configuración por cada servicio.
Si es necesario que la conexión sea con privilegios, se usará la contraseña que se encuentre en /etc/ldap.secret, y que estará con permisos 600 (como el punto anterior).
Tener la contraseña para autentificarse es necesario, con la configuración por defeto del slapd.conf, cuando el usuario root quiere cambiar la contraseña de otro usuario: si no es conexión autentificada, el servidor LDAP no le deja cambiarla. De otra forma cualquier usuario podría cambiar la contraseña de cualquier otro, solo lanzando la consulta al servidor LDAP.
Seguidamente, dejaremos el fichero /etc/pam_ldap.conf de forma parecida:
host 192.168.1.2 base dc=pinux,dc=info ldap_version 3 rootbinddn cn=admin,dc=pinux,dc=info # don't forget /etc/ldap.secret
Ahora ya tenemos la configuración general de PAM para funcionar con LDAP. Pasemos a la parte específica de cada servicio (ssh, su, passwd, etc.). Estaremos tocando los ficheros de configuración del cliente para que se autentifique contra el servidor.
ssh
Tenemos que ir al fichero /etc/pam.d/ssh y al menos añadir esas líneas:
auth sufficient pam_ldap.so account sufficient pam_ldap.so session sufficient pam_ldap.so password sufficient pam_ldap.so
al inicio del fichero.
Hace falta reinicir el servicio ssh
/etc/init.d/ssh restart
Lo dejo por las dudas, pero ya no hace falta
- En el caso del ssh tendremos seguramente que modificar en el fichero /etc/ssh/sshd_configel parámetro PAMAuthenticationViaKbdInt a yes. De otra forma no autentificaría de forma correcta.
su
Sirve para poder ejecutar el su con usuarios que están dados de alta en el LDAP.
En el fichero /etc/pam.d/su lo dejaremos parecido a:
auth sufficient pam_rootok.so auth sufficient pam_ldap.so auth required pam_unix.so use_first_pass account sufficient pam_ldap.so account required pam_unix.so session sufficient pam_ldap.so session required pam_unix.so
passwd
Este es para permitir cambiar las contraseñas de los usuarios. Lo podemos dejar así:
password sufficient pam_ldap.so password required pam_unix.so nullok obscure min=4 max=8
Es bastante útil dar de alta a los usuarios de forma normal y cambiarles la contraseña con el mismo passwd como root (si son pocos usuarios de pruebas, claro)
login
Lo dejaremos parecido a este:
auth required pam_nologin.so auth sufficient pam_ldap.so auth sufficient pam_unix.so shadow use_first_pass auth required pam_deny.so
Hay otras maneras de dejarlo, pero tenemos que ir con cuidado con el use_first_pass: si no lo ponemos los usuarios que estan dados de alta en LDAP se les pediría dos veces la contraseña (una validaría con /etc/passwd, y al no encontrar el usuario se lo pediría otra vez para validarlo contra LDAP.
Con los ejemplos vistos hasta ahora sería fácil hacer lo mismo en otros servicios (p. ej. proftpd, xlock, etc.)
También es relativamente fácil modificar los ficheros common-account common-auth common-password common-session para no tener que tocar el fichero de cada servicio, a costa de tener menos "personalización" por servicio.
Integracion con otros sistemas
Palm
http://www.yolinux.com/TUTORIALS/LinuxTutorialLDAPandPalmPilotAddressBook.html
Migracion a LDAP
migrationtools
The MigrationTools are a set of Perl scripts for migrating users, groups, aliases, hosts, netgroups, networks, protocols, RPCs, and services from existing nameservices (flat files, NIS, and NetInfo) to LDAP.
Website: http://www.padl.com/OSS/MigrationTools.html
dbd and hdb backends comparison
- hdb as sibling of bdb with the only significant difference of being able to rename (sub)trees, and thus move them around.
- Then there is one config difference: idlcachesize shoud be 4 x cachesize when using hdb. For bdb it can be way smaller than cachesize.
- One of main issues with hdb compared to bdb I see is the initial caching that needs to be done on large databases for it to get performant.
Update scripts
Add group member
If "net rpc vampire" does not import group member use this procedure to fix it
Create on NT4 a member.bat script with
net group group1 net group group2 net group groupN
Execute
member.bat > members.txt
Copy members.txt to linux box and run:
import fileinput import ldap import ldap.modlist as modlist dom1 = ldap.initialize("ldap://127.0.0.1:389/") dom1.simple_bind_s("cn=admin,dc=midominio,dc=com,dc=ar","mipassword") miembros_zone = 0 for line in fileinput.input( "members.txt" ): if ( line.startswith("Group name") ): grupo = line[15:].rstrip() print "Procesando grupo: %s" % grupo elif ( line.startswith("--------------") ): miembros_zone = 1 elif ( line.startswith("The command completed successfully") ): miembros_zone = 0 elif (miembros_zone == 1): line_miembros = line.split() for miembro in line_miembros: if not miembro.endswith("$"): dn="cn=%s,ou=groups,dc=midominio,dc=com,dc=ar" % grupo try: print " Agregando: %s" % miembro modlist = [(ldap.MOD_ADD,'memberuid',miembro)] dom1.modify_s(dn,modlist) except ldap.TYPE_OR_VALUE_EXISTS: print " Ya existe %s" % miembro dom1.unbind_s()
Create givenName, sn and cn from displayName
import ldap import ldap.modlist as modlist dom1 = ldap.initialize("ldap://127.0.0.1:389/") dom1.simple_bind_s("cn=admin,dc=midominio,dc=com,dc=ar","mipassword") baseDN = "ou=people,dc=midominio,dc=com,dc=ar" searchScope = ldap.SCOPE_SUBTREE ldap_result_id = dom1.search(baseDN, searchScope) result_set = [] while 1: result_type, result_data = dom1.result(ldap_result_id, 0) if (result_data == []): break else: if result_type == ldap.RES_SEARCH_ENTRY: if 'displayName' in result_data[0][1].keys(): dn = result_data[0][0] cn = result_data[0][1]['cn'][0] sn = result_data[0][1]['sn'][0] displayName = result_data[0][1]['displayName'][0] givenName = result_data[0][1]['givenName'][0] uid = result_data[0][1]['uid'][0] if cn == uid : nombres = displayName.split() cant_nom = len(nombres) if (cant_nom == 1): newGivenName = nombres[0] newSn = nombres[0] elif (cant_nom == 2): newGivenName = nombres[0] newSn = nombres[1] elif (cant_nom == 3): newGivenName = "%s %s" % (nombres[0], nombres[1]) newSn = nombres[2] elif (cant_nom == 4): newGivenName = "%s %s" % (nombres[0], nombres[1]) newSn = "%s %s" % (nombres[2], nombres[3]) else: newGivenName = "%s %s" % (nombres[0], nombres[1]) newSn = "%s %s %s" % (nombres[2], nombres[3], nombres[4]) old = {'cn':cn, 'givenName':givenName, 'sn':sn} new = {'cn':displayName, 'givenName':newGivenName, 'sn':newSn} ldif = modlist.modifyModlist(old,new) dom1.modify_s(dn,ldif) else: print "No se cambiara %s" % displayName
Create ou using description
Useful for NT4 migrated domains
import ldap import ldap.modlist as modlist dom1 = ldap.initialize("ldap://127.0.0.1:389/") dom1.simple_bind_s("cn=admin,dc=midominio,dc=com,dc=ar","pass") baseDN = "ou=people,dc=midominio,dc=com,dc=ar" searchScope = ldap.SCOPE_SUBTREE ldap_result_id = dom1.search(baseDN, searchScope) result_set = [] while 1: result_type, result_data = dom1.result(ldap_result_id, 0) if (result_data == []): break else: if result_type == ldap.RES_SEARCH_ENTRY: if 'description' in result_data[0][1].keys(): dn = result_data[0][0] description = result_data[0][1]['description'][0] old = {} new = {'ou':description} ldif = modlist.modifyModlist(old,new) dom1.modify_s(dn,ldif)
Problemas
Error: invalid structural object class chain (inetOrgPerson/account)
slapadd: dn="uid=PC001$,ou=computers,dc=midominio,dc=com,dc=ar" (line=5838): (65) invalid structural object class chain (inetOrgPerson/account)
Me apareció este error al querer importar un ldif sacado de un servidor que contiene una base de datos de un NT importado usando "net rpc vampire", se debe a que las "ou=computers" no puede tener las clases inetOrgPerson a la vez que la account:
Para resolver arme un pequeño script en python que remueve estas clases:
import fileinput computer = 0 for line in fileinput.input( "slapcat.ldif" ): if ( "ou=computers,dc=midominio,dc=com,dc=ar" in line ): computer = 1 elif ( line.startswith("# id=") ): computer = 0 elif ((computer == 1) & (("objectClass: inetOrgPerson" in line) | ("objectClass: organizationalPerson" in line))): continue print line,