Skip to content

Instantly share code, notes, and snippets.

@jirutka
Last active January 20, 2024 17:52
Show Gist options
  • Save jirutka/fda40e8ab14f9ca70887 to your computer and use it in GitHub Desktop.
Save jirutka/fda40e8ab14f9ca70887 to your computer and use it in GitHub Desktop.
Use LDAP to manage system users on Gentoo Linux

Use LDAP to manage system users on Linux

This configuration uses nsswitch and compat mode, which is supposedly obsolete, but much more convenient than alternatives.

Install packages

emerge -va sys-auth/nss_ldap sys-auth/pam_ldap sys-apps/unscd

Note: unscd (Micro Name Service Caching Daemon) is not necessary, but it’s recommended.

Configure

  1. Copy and edit ldap.conf to /etc/.

  2. Copy nsswitch.conf to /etc/.

  3. Copy system-auth and system-login to /etc/pam.d/.

  4. Copy useradd-nis and userdel-nis scripts to /usr/local/bin/.

  5. If you want to allow access for explicitly named users only, add this line to the end of /etc/passwd:

     +::::::/sbin/nologin
    
  6. (Optional) Enable and start unscd daemon:

     rc-update add unscd default
    

Allow specific user

Add entry to /etc/passwd as usual, but prefix it with + and omit fields which should be provided by LDAP. For example:

+flynn:::::/home/flynn:/bin/zsh

Note: In this configuration we’re not using LDAP groups, each LDAP user is assigned to gid 100. However, it can be simply modified to use LDAP groups, if you want to.

# /etc/ldap.conf
# This is the configuration file for the LDAP nameservice
# switch library and the LDAP PAM module.
#
# Specifies the URI(s) of the LDAP server(s) to connect to. Must be resolvable
# without using LDAP. The URI scheme may be ldap, ldapi, or ldaps, specifying
# LDAP over TCP, IPC and SSL respectively. A port number can be specified; the
# default port number for the selected protocol is used if omitted.
uri ldaps://ldap.example.org
# The distinguished name of the search base.
base dc=padl,dc=com
# The LDAP version to use. Default is 3 if supported by client library.
ldap_version 3
# The distinguished name to bind to the server with.
# Default is to bind anonymously.
#binddn uid=system,ou=Administrators,dc=padl,dc=com
# The credentials to bind with. Default is no credential.
#bindpw topsecret
# 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).
#rootbinddn cn=manager,dc=padl,dc=com
# The search scope; sub, one, or base.
scope one
# Search timelimit in seconds (0 for indefinite; default 0).
timelimit 5
# Bind/connect timelimit (0 for indefinite; default 30).
bind_timelimit 5
# Reconnect policy:
# hard_open: Reconnect to DSA with exponential backoff if opening connection
# failed.
# hard_init: Reconnect to DSA with exponential backoff if initializing
# connection failed.
# hard: Alias for hard_open.
# soft: Return immediately on server failure.
bind_policy soft
# Connection policy:
# persist: DSA connections are kept open (default)
# oneshot: DSA connections destroyed after request
#nss_connect_policy persist
# Idle timelimit; client will close connections (nss_ldap only) if the server
# has not been contacted for the number of seconds specified below.
#idle_timelimit 3600
# Use paged rseults
#nss_paged_results yes
# Pagesize: when paged results enable, used to set the pagesize to
# a custom value.
#pagesize 1000
# The filter to use when retrieving user information, additional to the login
# attribute value assertion (pam_login_attribute=<login>).
pam_filter objectclass=posixAccount
# The user ID attribute (defaults to 'uid').
#pam_login_attribute uid
# Search the root DSE for the password policy (defaults to 'no').
#pam_lookup_policy yes
# Group to enforce membership of.
#pam_groupdn cn=PAM,ou=Groups,dc=padl,dc=com
# Group member attribute.
pam_member_attribute memberuid
# Specify a minium or maximum UID number allowed.
pam_min_uid 1000
#pam_max_uid 65536
# Password change protocol:
# clear: Do not hash the password at all; presume the directory server will
# do it, if necessary (default).
# exop: Use the OpenLDAP password change extended operation to update the
# password.
# See man pam_ldap for more protocols.
pam_password exop
# Redirect users to a URL or somesuch on password changes.
#pam_password_prohibit_message Please visit http://internal to change your password.
# Use backlinks for answering initgroups().
#nss_initgroups backlink
# Enable support for RFC2307bis (distinguished names in group members).
#nss_schema rfc2307bis
# RFC2307bis naming contexts
# Syntax is:
# nss_base_XXX base?scope?filter
# where scope is {base,one,sub} and filter is a filter to be &'d with the
# default filter.
nss_base_passwd ou=People,dc=padl,dc=com?one
nss_base_shadow ou=People,dc=padl,dc=com?one
nss_base_group ou=Groups,dc=padl,dc=com?one
#nss_base_hosts ou=Hosts,dc=padl,dc=com?one
#nss_base_services ou=Services,dc=padl,dc=com?one
#nss_base_networks ou=Networks,dc=padl,dc=com?one
#nss_base_protocols ou=Protocols,dc=padl,dc=com?one
#nss_base_rpc ou=Rpc,dc=padl,dc=com?one
#nss_base_ethers ou=Ethers,dc=padl,dc=com?one
#nss_base_netmasks ou=Networks,dc=padl,dc=com?ne
#nss_base_bootparams ou=Ethers,dc=padl,dc=com?one
#nss_base_aliases ou=Aliases,dc=padl,dc=com?one
#nss_base_netgroup ou=Netgroup,dc=padl,dc=com?one
# Attribute/objectclass mapping
# Syntax:
# nss_map_attribute rfc2307attribute mapped_attribute
# nss_map_objectclass rfc2307objectclass mapped_objectclass
#
# NDS mappings
#nss_map_attribute uniqueMember member
#
# AuthPassword mappings
#nss_map_attribute userPassword authPassword
# OpenLDAP SSL mechanism
# start_tls mechanism uses the normal LDAP port, LDAPS typically 636
#ssl start_tls
###ssl on
# Gentoo note: Don't use 'ssl on' in 249/250. They are broken in some cases! Use start_tls instead.
# OpenLDAP SSL options
# Require and verify server certificate (yes/no).
# Default is to use libldap's default behavior, which can be configured in
# /etc/openldap/ldap.conf using the TLS_REQCERT setting. The default for
# OpenLDAP 2.0 and earlier is 'no', for 2.1 and later is 'yes'.
tls_checkpeer yes
# CA certificates for server certificate verification
# At least one of these are required if tls_checkpeer is 'yes'.
#tls_cacertfile /etc/ssl/ca.cert
tls_cacertdir /etc/ssl/certs
# SSL cipher suite
# See man ciphers for syntax.
#tls_ciphers TLSv1
# Timeout behavior
# For Gentoo's distribution of nss_ldap, as of 250-r1, we use these values
# (The hardwired constants in the code are changed to them as well):
nss_reconnect_tries 4 # number of times to double the sleep time
nss_reconnect_sleeptime 1 # initial sleep value
nss_reconnect_maxsleeptime 16 # max sleep value to cap at
nss_reconnect_maxconntries 2 # how many tries before sleeping
# This leads to a delay of 15 seconds (1+2+4+8=15) per lookup if the
# server is not available.
# Ignore users that we know are local.
nss_initgroups_ignoreusers root,portage,nobody,sshd,ldap,cron,postgres
# Override values for the specified attributes.
nss_override_attribute_value gidNumber 100
# /etc/nsswitch.conf
passwd: compat
shadow: files ldap
group: files
passwd_compat: ldap
hosts: files dns
networks: files dns
services: db files
protocols: db files
rpc: db files
ethers: db files
netmasks: files
netgroup: files
bootparams: files
automount: files
aliases: files
# /etc/pam.d/system-auth
auth required pam_env.so
auth sufficient pam_unix.so try_first_pass likeauth nullok
auth sufficient pam_ldap.so use_first_pass
auth required pam_deny.so
account sufficient pam_unix.so
account sufficient pam_ldap.so
account required pam_deny.so
password required pam_cracklib.so difok=2 minlen=8 dcredit=2 ocredit=2 retry=3
password sufficient pam_unix.so try_first_pass use_authtok nullok sha512 shadow
password sufficient pam_ldap.so use_first_pass use_authtok
password required pam_deny.so
session required pam_limits.so
session required pam_env.so
session required pam_unix.so
session optional pam_ldap.so
session optional pam_permit.so
# /etc/pam.d/system-login
auth required pam_tally2.so onerr=succeed
auth required pam_shells.so
auth required pam_nologin.so
auth include system-auth
account required pam_access.so
account required pam_nologin.so
account include system-auth
account required pam_tally2.so onerr=succeed
password include system-auth
session optional pam_loginuid.so
session required pam_env.so
session required pam_mkhomedir.so umask=0077
session optional pam_lastlog.so silent
session include system-auth
session optional pam_motd.so motd=/etc/motd
session optional pam_mail.so
#!/bin/bash
DEFAULT_SHELL=/bin/bash
############### Arguments ###############
usage() {
cat <<-EOF
This script adds entry to /etc/passwd for user in NIS/LDAP.
Usage: ${scriptname} [options] LOGIN
Options:
-d, --home-dir HOME_DIR home directory of the user.
-s, --shell SHELL login shell of the user.
-h, --help show this help.
EOF
}
scriptname=$(basename $0)
home=
shell="$DEFAULT_SHELL"
user=
while [ $# -gt 0 ]; do
case $1
in
-d | --home-dir)
home=$2
shift 2
;;
-h | --help)
usage
exit 0
;;
-s | --shell)
shell=$2
shift 2
;;
-*)
echo "${scriptname}: Unknown option $1" >&2
echo; usage
exit 1
;;
*)
user=$1
break
;;
esac
done
if [ -z "$user" ]; then
echo "${scriptname}: Missing LOGIN" >&2
echo; usage
exit 1
fi
if [ -z "$home" ]; then
home="/home/${user}"
fi
############### Main ###############
fail() {
echo "$1" >&2
exit 2
}
if ! id -u "$user" &>/dev/null; then
fail "User ${user} does not exist."
fi
if grep "^+\?${user}:" /etc/passwd &>/dev/null; then
fail "User ${user} is already defined in /etc/passwd"
fi
line="+${user}:::::${home}:${shell}"
sed -i "\$i ${line}" /etc/passwd
#!/bin/bash
############### Arguments ###############
usage() {
cat <<-EOF
This script removes NIS/LDAP user (entry prefixed with +) from
/etc/passwd, removes her from all supplementary groups and optionally
trashes her home.
Usage: ${scriptname} [options] LOGIN
Options:
-r, --remove remove home directory.
-h, --help show this help.
EOF
}
scriptname=$(basename $0)
delhome=
while [ $# -gt 0 ]; do
case $1
in
-r | --remove)
delhome='delhome'
shift
;;
-h | --help)
usage
exit 0
;;
-*)
echo "${scriptname}: Unknown option $1" >&2
echo; usage
exit 1
;;
*)
user=$1
break
;;
esac
done
if [ -z "$user" ]; then
echo "${scriptname}: Missing LOGIN" >&2
echo; usage
exit 1
fi
############### Main ###############
fail() {
echo "$1" >&2
exit 2
}
if ! grep "^+${user}:" /etc/passwd &>/dev/null; then
fail "User ${user} is not defined in /etc/passwd or is not a NIS user."
fi
if [ -n "$delhome" ]; then
home="$(getent passwd ${user} | cut -d: -f6)"
for p in '' '/' '/dev/null'; do
if [ "$home" == "$p" ]; then
fail "User's home is '${home}'; you really SHOULD NOT delete this..."
fi
done
read -p "Are you sure want to delete ${home} ? Type 'yes' to continue: " answer
if [ "$answer" == 'yes' ]; then
rm -Rfv -- "$home"
else
fail "Aborted."
fi
fi
# remove user from all supplementary groups
usermod -G '' "$user"
# remove user form passwd
sed -i "/+${user}:/d" /etc/passwd
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment