# SOME DESCRIPTIVE TITLE # Copyright (C) YEAR The FreeBSD Project # This file is distributed under the same license as the FreeBSD Documentation package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: FreeBSD Documentation VERSION\n" "POT-Creation-Date: 2024-12-29 08:30-0500\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #. type: YAML Front Matter: description #: documentation/content/en/articles/ldap-auth/_index.adoc:1 #, no-wrap msgid "Guide for the configuration of an LDAP server for authentication on FreeBSD" msgstr "" #. type: Title = #: documentation/content/en/articles/ldap-auth/_index.adoc:1 #: documentation/content/en/articles/ldap-auth/_index.adoc:12 #, no-wrap msgid "LDAP Authentication" msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:45 msgid "Abstract" msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:48 msgid "" "This document is intended as a guide for the configuration of an LDAP server " "(principally an OpenLDAP server) for authentication on FreeBSD. This is " "useful for situations where many servers need the same user accounts, for " "example as a replacement for NIS." msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:50 msgid "'''" msgstr "" #. type: Title == #: documentation/content/en/articles/ldap-auth/_index.adoc:54 #, no-wrap msgid "Preface" msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:58 msgid "" "This document is intended to give the reader enough of an understanding of " "LDAP to configure an LDAP server. This document will attempt to provide an " "explanation of package:net/nss_ldap[] and package:security/pam_ldap[] for " "use with client machines services for use with the LDAP server." msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:60 msgid "" "When finished, the reader should be able to configure and deploy a FreeBSD " "server that can host an LDAP directory, and to configure and deploy a " "FreeBSD server which can authenticate against an LDAP directory." msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:64 msgid "" "This article is not intended to be an exhaustive account of the security, " "robustness, or best practice considerations for configuring LDAP or the " "other services discussed herein. While the author takes care to do " "everything correctly, they do not address security issues beyond a general " "scope. This article should be considered to lay the theoretical groundwork " "only, and any actual implementation should be accompanied by careful " "requirement analysis." msgstr "" #. type: Title == #: documentation/content/en/articles/ldap-auth/_index.adoc:66 #, no-wrap msgid "Configuring LDAP" msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:71 msgid "" "LDAP stands for \"Lightweight Directory Access Protocol\" and is a subset of " "the X.500 Directory Access Protocol. Its most recent specifications are in " "http://www.ietf.org/rfc/rfc4510.txt[RFC4510] and friends. Essentially it is " "a database that expects to be read from more often than it is written to." msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:75 msgid "" "The LDAP server http://www.openldap.org/[OpenLDAP] will be used in the " "examples in this document; while the principles here should be generally " "applicable to many different servers, most of the concrete administration is " "OpenLDAP-specific. There are several server versions in ports, for example " "package:net/openldap26-server[]. Client servers will need the corresponding " "package:net/openldap26-client[] libraries." msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:78 msgid "" "There are (basically) two areas of the LDAP service which need " "configuration. The first is setting up a server to receive connections " "properly, and the second is adding entries to the server's directory so that " "FreeBSD tools know how to interact with it." msgstr "" #. type: Title === #: documentation/content/en/articles/ldap-auth/_index.adoc:80 #, no-wrap msgid "Setting Up the Server for Connections" msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:86 msgid "" "This section is specific to OpenLDAP. If you are using another server, you " "will need to consult that server's documentation." msgstr "" #. type: Block title #: documentation/content/en/articles/ldap-auth/_index.adoc:89 #: documentation/content/en/articles/ldap-auth/_index.adoc:94 #, no-wrap msgid "Installing OpenLDAP" msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:92 msgid "First, install OpenLDAP:" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:102 #, no-wrap msgid "" "# cd /usr/ports/net/openldap26-server\n" "# make install clean\n" msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:107 msgid "" "This installs the `slapd` and `slurpd` binaries, along with the required " "OpenLDAP libraries." msgstr "" #. type: Title ==== #: documentation/content/en/articles/ldap-auth/_index.adoc:109 #, no-wrap msgid "Configuring OpenLDAP" msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:112 msgid "Next we must configure OpenLDAP." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:115 msgid "" "You will want to require encryption in your connections to the LDAP server; " "otherwise your users' passwords will be transferred in plain text, which is " "considered insecure. The tools we will be using support two very similar " "kinds of encryption, SSL and TLS." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:118 msgid "" "TLS stands for \"Transportation Layer Security\". Services that employ TLS " "tend to connect on the _same_ ports as the same services without TLS; thus " "an SMTP server which supports TLS will listen for connections on port 25, " "and an LDAP server will listen on 389." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:121 msgid "" "SSL stands for \"Secure Sockets Layer\", and services that implement SSL do " "_not_ listen on the same ports as their non-SSL counterparts. Thus SMTPS " "listens on port 465 (not 25), HTTPS listens on 443, and LDAPS on 636." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:125 msgid "" "The reason SSL uses a different port than TLS is because a TLS connection " "begins as plain text, and switches to encrypted traffic after the `STARTTLS` " "directive. SSL connections are encrypted from the beginning. Other than " "that there are no substantial differences between the two." msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:129 msgid "We will adjust OpenLDAP to use TLS, as SSL is considered deprecated." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:132 msgid "" "Once OpenLDAP is installed via ports, the following configuration parameters " "in [.filename]#/usr/local/etc/openldap/slapd.conf# will enable TLS:" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:136 #, no-wrap msgid "security ssf=128\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:140 #, no-wrap msgid "" "TLSCertificateFile /path/to/your/cert.crt\n" "TLSCertificateKeyFile /path/to/your/cert.key\n" "TLSCACertificateFile /path/to/your/cacert.crt\n" msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:144 msgid "" "Here, `ssf=128` tells OpenLDAP to require 128-bit encryption for all " "connections, both search and update. This parameter may be configured based " "on the security needs of your site, but rarely you need to weaken it, as " "most LDAP client libraries support strong encryption." msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:147 msgid "" "The [.filename]#cert.crt#, [.filename]#cert.key#, and [.filename]#cacert." "crt# files are necessary for clients to authenticate _you_ as the valid LDAP " "server. If you simply want a server that runs, you can create a self-signed " "certificate with OpenSSL:" msgstr "" #. type: Block title #: documentation/content/en/articles/ldap-auth/_index.adoc:149 #, no-wrap msgid "Generating an RSA Key" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:160 #, no-wrap msgid "" "% openssl genrsa -out cert.key 1024\n" "Generating RSA private key, 1024 bit long modulus\n" "....................++++++\n" "...++++++\n" "e is 65537 (0x10001)\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:162 #, no-wrap msgid "% openssl req -new -key cert.key -out cert.csr\n" msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:171 msgid "" "At this point you should be prompted for some values. You may enter " "whatever values you like; however, it is important the \"Common Name\" value " "be the fully qualified domain name of the OpenLDAP server. In our case, and " "the examples here, the server is _server.example.org_. Incorrectly setting " "this value will cause clients to fail when making connections. This can the " "cause of great frustration, so ensure that you follow these steps closely." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:173 msgid "Finally, the certificate signing request needs to be signed:" msgstr "" #. type: Block title #: documentation/content/en/articles/ldap-auth/_index.adoc:175 #, no-wrap msgid "Self-signing the Certificate" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:185 #, no-wrap msgid "" "% openssl x509 -req -in cert.csr -days 365 -signkey cert.key -out cert.crt\n" "Signature ok\n" "subject=/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd\n" "Getting Private key\n" msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:192 msgid "" "This will create a self-signed certificate that can be used for the " "directives in [.filename]#slapd.conf#, where [.filename]#cert.crt# and [." "filename]#cacert.crt# are the same file. If you are going to use many " "OpenLDAP servers (for replication via `slurpd`) you will want to see " "crossref:ldap-auth[ssl-ca, OpenSSL Certificates for LDAP] to generate a CA " "key and use it to sign individual server certificates." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:194 msgid "Once this is done, put the following in [.filename]#/etc/rc.conf#:" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:198 #, no-wrap msgid "slapd_enable=\"YES\"\n" msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:203 msgid "" "Then run `/usr/local/etc/rc.d/slapd start`. This should start OpenLDAP. " "Confirm that it is listening on 389 with" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:208 #, no-wrap msgid "" "% sockstat -4 -p 389\n" "ldap slapd 3261 7 tcp4 *:389 *:*\n" msgstr "" #. type: Title ==== #: documentation/content/en/articles/ldap-auth/_index.adoc:211 #, no-wrap msgid "Configuring the Client" msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:215 msgid "" "Install the package:net/openldap26-client[] port for the OpenLDAP " "libraries. The client machines will always have OpenLDAP libraries since " "that is all package:security/pam_ldap[] and package:net/nss_ldap[] support, " "at least for the moment." msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:218 msgid "" "The configuration file for the OpenLDAP libraries is [.filename]#/usr/local/" "etc/openldap/ldap.conf#. Edit this file to contain the following values:" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:225 #, no-wrap msgid "" "base dc=example,dc=org\n" "uri ldap://server.example.org/\n" "ssl start_tls\n" "tls_cacert /path/to/your/cacert.crt\n" msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:230 msgid "" "It is important that your clients have access to [.filename]#cacert.crt#, " "otherwise they will not be able to connect." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:237 msgid "" "There are two files called [.filename]#ldap.conf#. The first is this file, " "which is for the OpenLDAP libraries and defines how to talk to the server. " "The second is [.filename]#/usr/local/etc/ldap.conf#, and is for pam_ldap." msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:242 msgid "" "At this point you should be able to run `ldapsearch -Z` on the client " "machine; `-Z` means \"use TLS\". If you encounter an error, then something " "is configured wrong; most likely it is your certificates. Use man:" "openssl[1]'s `s_client` and `s_server` to ensure you have them configured " "and signed properly." msgstr "" #. type: Title === #: documentation/content/en/articles/ldap-auth/_index.adoc:244 #, no-wrap msgid "Entries in the Database" msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:249 msgid "" "Authentication against an LDAP directory is generally accomplished by " "attempting to bind to the directory as the connecting user. This is done by " "establishing a \"simple\" bind on the directory with the user name " "supplied. If there is an entry with the `uid` equal to the user name and " "that entry's `userPassword` attribute matches the password supplied, then " "the bind is successful." msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:251 msgid "" "The first thing we have to do is figure out is where in the directory our " "users will live." msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:255 msgid "" "The base entry for our database is `dc=example,dc=org`. The default " "location for users that most clients seem to expect is something like " "`ou=people,_base_`, so that is what will be used here. However keep in mind " "that this is configurable." msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:257 msgid "So the ldif entry for the `people` organizational unit will look like:" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:264 #, no-wrap msgid "" "dn: ou=people,dc=example,dc=org\n" "objectClass: top\n" "objectClass: organizationalUnit\n" "ou: people\n" msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:267 msgid "All users will be created as subentries of this organizational unit." msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:272 msgid "" "Some thought might be given to the object class your users will belong to. " "Most tools by default will use `people`, which is fine if you simply want to " "provide entries against which to authenticate. However, if you are going to " "store user information in the LDAP database as well, you will probably want " "to use `inetOrgPerson`, which has many useful attributes. In either case, " "the relevant schemas need to be loaded in [.filename]#slapd.conf#." msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:275 msgid "" "For this example we will use the `person` object class. If you are using " "`inetOrgPerson`, the steps are basically identical, except that the `sn` " "attribute is required." msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:277 msgid "To add a test-user named `tuser`, the ldif would be:" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:291 #, no-wrap msgid "" "dn: uid=tuser,ou=people,dc=example,dc=org\n" "objectClass: person\n" "objectClass: posixAccount\n" "objectClass: shadowAccount\n" "objectClass: top\n" "uidNumber: 10000\n" "gidNumber: 10000\n" "homeDirectory: /home/tuser\n" "loginShell: /bin/csh\n" "uid: tuser\n" "cn: tuser\n" msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:294 msgid "" "I start my LDAP users' UIDs at 10000 to avoid collisions with system " "accounts; you can configure whatever number you wish here, as long as it is " "less than 65536." msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:297 msgid "" "We also need group entries. They are as configurable as user entries, but " "we will use the defaults below:" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:304 #, no-wrap msgid "" "dn: ou=groups,dc=example,dc=org\n" "objectClass: top\n" "objectClass: organizationalUnit\n" "ou: groups\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:310 #, no-wrap msgid "" "dn: cn=tuser,ou=groups,dc=example,dc=org\n" "objectClass: posixGroup\n" "objectClass: top\n" "gidNumber: 10000\n" "cn: tuser\n" msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:314 msgid "" "To enter these into your database, you can use `slapadd` or `ldapadd` on a " "file containing these entries. Alternatively, you can use package:sysutils/" "ldapvi[]." msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:317 msgid "" "The `ldapsearch` utility on the client machine should now return these " "entries. If it does, your database is properly configured to be used as an " "LDAP authentication server." msgstr "" #. type: Title == #: documentation/content/en/articles/ldap-auth/_index.adoc:319 #, no-wrap msgid "Client Configuration" msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:323 msgid "" "The client should already have OpenLDAP libraries from crossref:ldap-" "auth[ldap-connect-client,Configuring the Client], but if you are installing " "several client machines you will need to install package:net/openldap26-" "client[] on each of them." msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:325 msgid "" "FreeBSD requires two ports to be installed to authenticate against an LDAP " "server, package:security/pam_ldap[] and package:net/nss_ldap[]." msgstr "" #. type: Title === #: documentation/content/en/articles/ldap-auth/_index.adoc:327 #, no-wrap msgid "Authentication" msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:330 msgid "" "package:security/pam_ldap[] is configured via [.filename]#/usr/local/etc/" "ldap.conf#." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:335 msgid "" "This is a _different file_ than the OpenLDAP library functions' " "configuration file, [.filename]#/usr/local/etc/openldap/ldap.conf#; however, " "it takes many of the same options; in fact it is a superset of that file. " "For the rest of this section, references to [.filename]#ldap.conf# will mean " "[.filename]#/usr/local/etc/ldap.conf#." msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:339 msgid "" "Thus, we will want to copy all of our original configuration parameters from " "[.filename]#openldap/ldap.conf# to the new [.filename]#ldap.conf#. Once " "this is done, we want to tell package:security/pam_ldap[] what to look for " "on the directory server." msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:342 msgid "" "We are identifying our users with the `uid` attribute. To configure this " "(though it is the default), set the `pam_login_attribute` directive in [." "filename]#ldap.conf#:" msgstr "" #. type: Block title #: documentation/content/en/articles/ldap-auth/_index.adoc:344 #, no-wrap msgid "Setting `pam_login_attribute`" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:351 #, no-wrap msgid "pam_login_attribute uid\n" msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:359 msgid "" "With this set, package:security/pam_ldap[] will search the entire LDAP " "directory under `base` for the value `uid=_username_`. If it finds one and " "only one entry, it will attempt to bind as that user with the password it " "was given. If it binds correctly, then it will allow access. Otherwise it " "will fail." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:365 msgid "" "Users whose shell is not in [.filename]#/etc/shells# will not be able to log " "in. This is particularly important when Bash is set as the user shell on " "the LDAP server. Bash is not included with a default installation of " "FreeBSD. When installed from a package or port, it is located at [." "filename]#/usr/local/bin/bash#. Verify that the path to the shell on the " "server is set correctly:" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:369 #, no-wrap msgid "% getent passwd username\n" msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:374 msgid "" "There are two choices when the output shows `/bin/bash` in the last column. " "The first is to change the user's entry on the LDAP server to [.filename]#/" "usr/local/bin/bash#. The second option is to create a symlink on the LDAP " "client computer so Bash is found at the correct location:" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:378 #, no-wrap msgid "# ln -s /usr/local/bin/bash /bin/bash\n" msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:382 msgid "" "Make sure that [.filename]#/etc/shells# contains entries for both `/usr/" "local/bin/bash` and `/bin/bash`. The user will then be able to log in to " "the system with Bash as their shell." msgstr "" #. type: Title ==== #: documentation/content/en/articles/ldap-auth/_index.adoc:384 #, no-wrap msgid "PAM" msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:388 msgid "" "PAM, which stands for \"Pluggable Authentication Modules\", is the method by " "which FreeBSD authenticates most of its sessions. To tell FreeBSD we wish " "to use an LDAP server, we will have to add a line to the appropriate PAM " "file." msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:390 msgid "" "Most of the time the appropriate PAM file is [.filename]#/etc/pam.d/sshd#, " "if you want to use SSH (remember to set the relevant options in [.filename]#/" "etc/ssh/sshd_config#, otherwise SSH will not use PAM)." msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:392 msgid "To use PAM for authentication, add the line" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:396 #, no-wrap msgid "auth sufficient /usr/local/lib/pam_ldap.so no_warn\n" msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:399 msgid "" "Exactly where this line shows up in the file and which options appear in the " "fourth column determine the exact behavior of the authentication mechanism; " "see man:pam[d]" msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:402 msgid "" "With this configuration you should be able to authenticate a user against an " "LDAP directory. PAM will perform a bind with your credentials, and if " "successful will tell SSH to allow access." msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:406 msgid "" "However it is not a good idea to allow _every_ user in the directory into " "_every_ client machine. With the current configuration, all that a user " "needs to log into a machine is an LDAP entry. Fortunately there are a few " "ways to restrict user access." msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:409 msgid "" "[.filename]#ldap.conf# supports a `pam_groupdn` directive; every account " "that connects to this machine needs to be a member of the group specified " "here. For example, if you have" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:413 #, no-wrap msgid "pam_groupdn cn=servername,ou=accessgroups,dc=example,dc=org\n" msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:417 msgid "" "in [.filename]#ldap.conf#, then only members of that group will be able to " "log in. There are a few things to bear in mind, however." msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:420 msgid "" "Members of this group are specified in one or more `memberUid` attributes, " "and each attribute must have the full distinguished name of the member. So " "`memberUid: someuser` will not work; it must be:" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:424 #, no-wrap msgid "memberUid: uid=someuser,ou=people,dc=example,dc=org\n" msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:430 msgid "" "Additionally, this directive is not checked in PAM during authentication, it " "is checked during account management, so you will need a second line in your " "PAM files under `account`. This will require, in turn, _every_ user to be " "listed in the group, which is not necessarily what we want. To avoid " "blocking users that are not in LDAP, you should enable the " "`ignore_unknown_user` attribute. Finally, you should set the " "`ignore_authinfo_unavail` option so that you are not locked out of every " "computer when the LDAP server is unavailable." msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:432 msgid "Your [.filename]#pam.d/sshd# might then end up looking like this:" msgstr "" #. type: Block title #: documentation/content/en/articles/ldap-auth/_index.adoc:434 #, no-wrap msgid "Sample [.filename]#pam.d/sshd#" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:445 #, no-wrap msgid "" "auth required pam_nologin.so no_warn\n" "auth sufficient pam_opie.so no_warn no_fake_prompts\n" "auth requisite pam_opieaccess.so no_warn allow_local\n" "auth sufficient /usr/local/lib/pam_ldap.so no_warn\n" "auth required pam_unix.so no_warn try_first_pass\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:448 #, no-wrap msgid "" "account required pam_login_access.so\n" "account required /usr/local/lib/pam_ldap.so no_warn ignore_authinfo_unavail ignore_unknown_user\n" msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:457 msgid "" "Since we are adding these lines specifically to [.filename]#pam.d/sshd#, " "this will only have an effect on SSH sessions. LDAP users will be unable to " "log in at the console. To change this behavior, examine the other files in " "[.filename]#/etc/pam.d# and modify them accordingly." msgstr "" #. type: Title === #: documentation/content/en/articles/ldap-auth/_index.adoc:460 #, no-wrap msgid "Name Service Switch" msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:464 msgid "" "NSS is the service that maps attributes to names. So, for example, if a " "file is owned by user `1001`, an application will query NSS for the name of " "`1001`, and it might get `bob` or `ted` or whatever the user's name is." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:466 msgid "" "Now that our user information is kept in LDAP, we need to tell NSS to look " "there when queried." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:471 msgid "" "The package:net/nss_ldap[] port does this. It uses the same configuration " "file as package:security/pam_ldap[], and should not need any extra " "parameters once it is installed. Instead, what is left is simply to edit [." "filename]#/etc/nsswitch.conf# to take advantage of the directory. Simply " "replace the following lines:" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:476 #, no-wrap msgid "" "group: compat\n" "passwd: compat\n" msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:479 msgid "with" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:484 #, no-wrap msgid "" "group: files ldap\n" "passwd: files ldap\n" msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:487 msgid "This will allow you to map usernames to UIDs and UIDs to usernames." msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:489 msgid "Congratulations! You should now have working LDAP authentication." msgstr "" #. type: Title === #: documentation/content/en/articles/ldap-auth/_index.adoc:491 #, no-wrap msgid "Caveats" msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:498 msgid "" "Unfortunately, as of the time this was written FreeBSD did not support " "changing user passwords with man:passwd[1]. As a result of this, most " "administrators are left to implement a solution themselves. I provide some " "examples here. Note that if you write your own password change script, " "there are some security issues you should be made aware of; see crossref:" "ldap-auth[security-passwd, Password Storage]" msgstr "" #. type: Block title #: documentation/content/en/articles/ldap-auth/_index.adoc:500 #, no-wrap msgid "Shell Script for Changing Passwords" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:507 #, no-wrap msgid "#!/bin/sh\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:513 #, no-wrap msgid "" "stty -echo\n" "read -p \"Old Password: \" oldp; echo\n" "read -p \"New Password: \" np1; echo\n" "read -p \"Retype New Password: \" np2; echo\n" "stty echo\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:518 #, no-wrap msgid "" "if [ \"$np1\" != \"$np2\" ]; then\n" " echo \"Passwords do not match.\"\n" " exit 1\n" "fi\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:523 #, no-wrap msgid "" "ldappasswd -D uid=\"$USER\",ou=people,dc=example,dc=org \\\n" " -w \"$oldp\" \\\n" " -a \"$oldp\" \\\n" " -s \"$np1\"\n" msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:532 msgid "" "This script does hardly any error checking, but more important it is very " "cavalier about how it stores your passwords. If you do anything like this, " "at least adjust the `security.bsd.see_other_uids` sysctl value:" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:536 #, no-wrap msgid "# sysctl security.bsd.see_other_uids=0\n" msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:543 msgid "" "A more flexible (and probably more secure) approach can be used by writing a " "custom program, or even a web interface. The following is part of a Ruby " "library that can change LDAP passwords. It sees use both on the command " "line, and on the web." msgstr "" #. type: Block title #: documentation/content/en/articles/ldap-auth/_index.adoc:545 #, no-wrap msgid "Ruby Script for Changing Passwords" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:555 #, no-wrap msgid "" "require 'ldap'\n" "require 'base64'\n" "require 'digest'\n" "require 'password' # ruby-password\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:558 #, no-wrap msgid "" "ldap_server = \"ldap.example.org\"\n" "luser = \"uid=#{ENV['USER']},ou=people,dc=example,dc=org\"\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:563 #, no-wrap msgid "" "# get the new password, check it, and create a salted hash from it\n" "def get_password\n" " pwd1 = Password.get(\"New Password: \")\n" " pwd2 = Password.get(\"Retype New Password: \")\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:566 #, no-wrap msgid "" " raise if pwd1 != pwd2\n" " pwd1.check # check password strength\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:572 #, no-wrap msgid "" " salt = rand.to_s.gsub(/0\\./, '')\n" " pass = pwd1.to_s\n" " hash = \"{SSHA}\"+Base64.encode64(Digest::SHA1.digest(\"#{pass}#{salt}\")+salt).chomp!\n" " return hash\n" "end\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:575 #, no-wrap msgid "" "oldp = Password.get(\"Old Password: \")\n" "newp = get_password\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:578 #, no-wrap msgid "" "# We'll just replace it. That we can bind proves that we either know\n" "# the old password or are an admin.\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:582 #, no-wrap msgid "" "replace = LDAP::Mod.new(LDAP::LDAP_MOD_REPLACE | LDAP::LDAP_MOD_BVALUES,\n" " \"userPassword\",\n" " [newp])\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:587 #, no-wrap msgid "" "conn = LDAP::SSLConn.new(ldap_server, 389, true)\n" "conn.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3)\n" "conn.bind(luser, oldp)\n" "conn.modify(luser, [replace])\n" msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:592 msgid "" "Although not guaranteed to be free of security holes (the password is kept " "in memory, for example) this is cleaner and more flexible than a simple `sh` " "script." msgstr "" #. type: Title == #: documentation/content/en/articles/ldap-auth/_index.adoc:594 #, no-wrap msgid "Security Considerations" msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:597 msgid "" "Now that your machines (and possibly other services) are authenticating " "against your LDAP server, this server needs to be protected at least as well " "as [.filename]#/etc/master.passwd# would be on a regular server, and " "possibly even more so since a broken or cracked LDAP server would break " "every client service." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:600 msgid "" "Remember, this section is not exhaustive. You should continually review " "your configuration and procedures for improvements." msgstr "" #. type: Title === #: documentation/content/en/articles/ldap-auth/_index.adoc:602 #, no-wrap msgid "Setting Attributes Read-only" msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:606 msgid "" "Several attributes in LDAP should be read-only. If left writable by the " "user, for example, a user could change his `uidNumber` attribute to `0` and " "get `root` access!" msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:610 msgid "" "To begin with, the `userPassword` attribute should not be world-readable. " "By default, anyone who can connect to the LDAP server can read this " "attribute. To disable this, put the following in [.filename]#slapd.conf#:" msgstr "" #. type: Block title #: documentation/content/en/articles/ldap-auth/_index.adoc:612 #, no-wrap msgid "Hide Passwords" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:623 #: documentation/content/en/articles/ldap-auth/_index.adoc:649 #, no-wrap msgid "" "access to dn.subtree=\"ou=people,dc=example,dc=org\"\n" " attrs=userPassword\n" " by self write\n" " by anonymous auth\n" " by * none\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:627 #: documentation/content/en/articles/ldap-auth/_index.adoc:656 #, no-wrap msgid "" "access to *\n" " by self write\n" " by * read\n" msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:632 msgid "" "This will disallow reading of the `userPassword` attribute, while still " "allowing users to change their own passwords." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:636 msgid "" "Additionally, you'll want to keep users from changing some of their own " "attributes. By default, users can change any attribute (except for those " "which the LDAP schemas themselves deny changes), such as `uidNumber`. To " "close this hole, modify the above to" msgstr "" #. type: Block title #: documentation/content/en/articles/ldap-auth/_index.adoc:638 #, no-wrap msgid "Read-only Attributes" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:652 #, no-wrap msgid "" "access to attrs=homeDirectory,uidNumber,gidNumber\n" " by * read\n" msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:661 msgid "This will stop users from being able to masquerade as other users." msgstr "" #. type: Title === #: documentation/content/en/articles/ldap-auth/_index.adoc:663 #, no-wrap msgid "`root` Account Definition" msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:668 msgid "" "Often the `root` or manager account for the LDAP service will be defined in " "the configuration file. OpenLDAP supports this, for example, and it works, " "but it can lead to trouble if [.filename]#slapd.conf# is compromised. It " "may be better to use this only to bootstrap yourself into LDAP, and then " "define a `root` account there." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:672 msgid "" "Even better is to define accounts that have limited permissions, and omit a " "`root` account entirely. For example, users that can add or remove user " "accounts are added to one group, but they cannot themselves change the " "membership of this group. Such a security policy would help mitigate the " "effects of a leaked password." msgstr "" #. type: Block title #: documentation/content/en/articles/ldap-auth/_index.adoc:674 #: documentation/content/en/articles/ldap-auth/_index.adoc:680 #, no-wrap msgid "Creating a Management Group" msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:678 msgid "" "Say you want your IT department to be able to change home directories for " "users, but you do not want all of them to be able to add or remove users. " "The way to do this is to add a group for these admins:" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:693 #, no-wrap msgid "" "dn: cn=homemanagement,dc=example,dc=org\n" "objectClass: top\n" "objectClass: posixGroup\n" "cn: homemanagement\n" "gidNumber: 121 # required for posixGroup\n" "memberUid: uid=tuser,ou=people,dc=example,dc=org\n" "memberUid: uid=user2,ou=people,dc=example,dc=org\n" msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:698 msgid "And then change the permissions attributes in [.filename]#slapd.conf#:" msgstr "" #. type: Block title #: documentation/content/en/articles/ldap-auth/_index.adoc:700 #, no-wrap msgid "ACLs for a Home Directory Management Group" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:710 #, no-wrap msgid "" "access to dn.subtree=\"ou=people,dc=example,dc=org\"\n" " attr=homeDirectory\n" " by dn=\"cn=homemanagement,dc=example,dc=org\"\n" " dnattr=memberUid write\n" msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:715 msgid "Now `tuser` and `user2` can change other users' home directories." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:719 msgid "" "In this example we have given a subset of administrative power to certain " "users without giving them power in other domains. The idea is that soon no " "single user account has the power of a `root` account, but every power root " "had is had by at least one user. The `root` account then becomes " "unnecessary and can be removed." msgstr "" #. type: Title === #: documentation/content/en/articles/ldap-auth/_index.adoc:721 #, no-wrap msgid "Password Storage" msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:725 msgid "" "By default OpenLDAP will store the value of the `userPassword` attribute as " "it stores any other data: in the clear. Most of the time it is base 64 " "encoded, which provides enough protection to keep an honest administrator " "from knowing your password, but little else." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:728 msgid "" "It is a good idea, then, to store passwords in a more secure format, such as " "SSHA (salted SHA). This is done by whatever program you use to change " "users' passwords." msgstr "" #. type: Title == #: documentation/content/en/articles/ldap-auth/_index.adoc:733 #, no-wrap msgid "Useful Aids" msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:736 msgid "" "There are a few other programs that might be useful, particularly if you " "have many users and do not want to configure everything manually." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:739 msgid "" "package:security/pam_mkhomedir[] is a PAM module that always succeeds; its " "purpose is to create home directories for users which do not have them. If " "you have dozens of client servers and hundreds of users, it is much easier " "to use this and set up skeleton directories than to prepare every home " "directory." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:743 msgid "" "package:sysutils/ldapvi[] is a great utility for editing LDAP values in an " "LDIF-like syntax. The directory (or subsection of the directory) is " "presented in the editor chosen by the `EDITOR` environment variable. This " "makes it easy to enable large-scale changes in the directory without having " "to write a custom tool." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:746 msgid "" "package:security/openssh-portable[] has the ability to contact an LDAP " "server to verify SSH keys. This is extremely nice if you have many servers " "and do not want to copy your public keys across all of them." msgstr "" #. type: Title == #: documentation/content/en/articles/ldap-auth/_index.adoc:751 #, no-wrap msgid "OpenSSL Certificates for LDAP" msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:755 msgid "" "If you are hosting two or more LDAP servers, you will probably not want to " "use self-signed certificates, since each client will have to be configured " "to work with each certificate. While this is possible, it is not nearly as " "simple as creating your own certificate authority, and signing your servers' " "certificates with that." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:757 msgid "" "The steps here are presented as they are with very little attempt at " "explaining what is going on-further explanation can be found in man:" "openssl[1] and its friends." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:760 msgid "" "To create a certificate authority, we simply need a self-signed certificate " "and key. The steps for this again are" msgstr "" #. type: Block title #: documentation/content/en/articles/ldap-auth/_index.adoc:762 #, no-wrap msgid "Creating a Certificate" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:771 #, no-wrap msgid "" "% openssl genrsa -out root.key 1024\n" "% openssl req -new -key root.key -out root.csr\n" "% openssl x509 -req -days 1024 -in root.csr -signkey root.key -out root.crt\n" msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:777 msgid "" "These will be your root CA key and certificate. You will probably want to " "encrypt the key and store it in a cool, dry place; anyone with access to it " "can masquerade as one of your LDAP servers." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:780 msgid "" "Next, using the first two steps above create a key [.filename]#ldap-server-" "one.key# and certificate signing request [.filename]#ldap-server-one.csr#. " "Once you sign the signing request with [.filename]#root.key#, you will be " "able to use [.filename]#ldap-server-one.*# on your LDAP servers." msgstr "" #. type: Plain text #: documentation/content/en/articles/ldap-auth/_index.adoc:784 msgid "" "Do not forget to use the fully qualified domain name for the \"common name\" " "attribute when generating the certificate signing request; otherwise clients " "will reject a connection with you, and it can be very tricky to diagnose." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:787 msgid "To sign the key, use `-CA` and `-CAkey` instead of `-signkey`:" msgstr "" #. type: Block title #: documentation/content/en/articles/ldap-auth/_index.adoc:789 #, no-wrap msgid "Signing as a Certificate Authority" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:798 #, no-wrap msgid "" "% openssl x509 -req -days 1024 \\\n" "-in ldap-server-one.csr -CA root.crt -CAkey root.key \\\n" "-out ldap-server-one.crt\n" msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:803 msgid "" "The resulting file will be the certificate that you can use on your LDAP " "servers." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/ldap-auth/_index.adoc:804 msgid "" "Finally, for clients to trust all your servers, distribute [.filename]#root." "crt# (the __certificate__, not the key!) to each client, and specify it in " "the `TLSCACertificateFile` directive in [.filename]#ldap.conf#." msgstr ""