OpenLDAP
Contenido
Filters
Operators
& = and | = or ! = not ~= = approx equal >= = greater than or equal <= = less than or equal * = any
- Examples
(objectclass=posixAccount) (cn=Mickey M*) (|(uid=fred)(uid=bill)) (&(|(uid=jack)(uid=jill))(objectclass=posixAccount))
Searching for Special Characters
If you need to search for a pattern that includes a special character (* ) ( \ or NULL) it must be escaped using the format '\code' (the code is actually the 2 hexadecimal characters representing the ASCII character). Similarly any binary value may be search for by using its hexadecimal value.
\2a replaces or escapes * \28 replaces or escapes ( \29 replaces or escapes ) \5c replaces or escapes \ \00 replaces or escapes NUL \xx search for hexadecimal value where xx lies in range 00 - FF
- Escaped Search Examples
(cn=*\2a*) # searches for * anywhere in the cn (file=d:\5cmyfile.html) # searches for d:\myfile (description=*\28*\29) # searches for both ( and ) anywhere and in that order (bin=\5b\04) # searches for binary values 5b04
How do I match 3 attributes?
This gets a little tricky:
(&(&(objectClass=user)(objectClass=top))(objectClass=person))
Notice how we weave one query into another. For 4 attributes, this would be:
(&(&(&(objectClass=top)(objectClass=person))(objectClass=organizationalPerson))(objectClass=user))
And so on.
Matching Components of Distinguished Names
It is possible to declare that any part of the base DN attribute data values may also be included in the search. This may be done using the keyword dn within the search expression as shown below. You may want to match part of a DN, for instance when you need to look for your groups in two subtrees of your server.
(&(objectClass=group)(|(ou:dn:=Chicago)(ou:dn:=Miami)))
will find groups with an OU component of their DN which is either 'Chicago' or 'Miami'.
More: http://www.zytrax.com/books/ldap/apa/component.html
Using 'not'
To exclude entities which match an expression, use '!'. Note that this must be represented as the entity '!' in your XML file.
(&(objectClass=group)(&(ou:dn:=Chicago)(!(ou:dn:=Wrigleyville))))
will find all Chicago groups except those with a Wrigleyville OU component.
Note the extra parentheses:
(!(<expression>))
- http://www.faqs.org/rfcs/rfc2254.html
- http://confluence.atlassian.com/display/DEV/How+to+write+a+LDAP+search+filter
LDAP URL
<ldapurl> ::= "ldap://" [ <hostport> ] "/" <dn> [ "?" <attributes> [ "?" <scope> "?" <filter> ] ] <hostport> ::= <hostname> [ ":" <portnumber> ] <dn> ::= a string as defined in RFC 1485 <attributes> ::= NULL | <attributelist> <attributelist> ::= <attributetype> | <attributetype> [ "," <attributelist> ] <attributetype> ::= a string as defined in RFC 1777 <scope> ::= "base" | "one" | "sub" <filter> ::= a string as defined in RFC 1558
Explanations
- DN
- Distinguished name
- Attribute list
- List of attributes you want returned
- Scope
- base = base object search
- one = one level search
- sub = subtree search
- Filter
- Standard LDAP search filter
- Examples
- ldap://foo.bar.com/dc=bar,dc=com
- ldap://argle.bargle.com/dc=bar,dc=com??sub?uid=barney
- ldap://ldap.bedrock.com/dc=bar,dc=com?cn?sub?uid=barney
Definition taken from RFC1959
Procedimiento de instalaccion de servidor OpenLDAP
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"
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
Python script to 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 = False 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 = True elif line.startswith("The command completed successfully"): miembros_zone = False elif miembros_zone: 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()
Python script to 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 True: 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]: 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
Python script to 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 True: 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]: 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 = False for line in fileinput.input( "slapcat.ldif" ): if "ou=computers,dc=midominio,dc=com,dc=ar" in line: computer = True elif line.startswith("# id="): computer = False elif computer and ("objectClass: inetOrgPerson" in line or "objectClass: organizationalPerson" in line): continue print line,
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
Referencias
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