Saturday, May 9, 2009

Fedora Directory Server and Solaris 10

Now something more meaty: configuring Solaris 10 to use Fedora Directory Server as an LDAP source of users, groups and authentication. This information is sourced from the FDS Project and Sun documentation.

In order for PAM authentication to work, the Solaris 10 server needs to be recently patched. I'm not sure which patch it is specifically, but patch level 138889-07 (from 'uname -a') will be enough.

Create Fedora Directory Server profile

This step should only need to be done once per FDS cluster, multiple Solaris 10 machines can use the same profile.

Solaris takes the stance that everything should be stored in the directory server, including how to talk to the directory server. Only a minimal amount of information is stored on the Solaris host, namely which LDAP server to talk to and any proxy username and password to use to connect to the LDAP server.

A blank FDS install won't have the necessary structure or schema to support Solaris. The FDS install requires the DUAConfigProfile schema, which is available from the Fedora Project.

Once this schema is imported, there's a script on Solaris 10 that can be used to create the base directory structure that Solaris uses for LDAP. A lot of what this script creates is not used, the most important thing is the ou=profiles addition which stores instructions on how Solaris machines connect to the LDAP servers.

The script also adds a mandatory nisDomain attribute to the base of the directory. Fedora Directory Server should have a schema for the objectClass nisDomainObject, but if not, you'll have to go looking for one.
dn: dc=somedomain,dc=com,dc=au
nisDomain: somedomain.com.au
objectClass: nisDomainObject
The script is located at /usr/lib/ldap/idsconfig, it needs one slight modification to make sure it executes correctly. Here is a patch to change the allowed IDS_MAJVER to match what Fedora Directory Server presents (version 1 in this case). If after applying this patch it still complains about the wrong version, just edit the 'if' statement to allow the major version number that your version of FDS is quoting.
--- idsconfig.backup    Tue Jan 13 12:14:50 2009
+++ idsconfig Tue Jan 13 12:18:45 2009
@@ -1191,8 +1191,8 @@
IDS_VER=`cat ${TMPDIR}/checkDSver`
IDS_MAJVER=`${ECHO} ${IDS_VER} | cut -f1 -d.`
IDS_MINVER=`${ECHO} ${IDS_VER} | cut -f2 -d.`
- if [ "${IDS_MAJVER}" != "5" ] && [ "${IDS_MAJVER}" != "6" ]; then
- ${ECHO} "ERROR: $PROG only works with JES DS version 5.x and 6.x, not ${IDS_VER}."
+ if [ "${IDS_MAJVER}" != "5" ] && [ "${IDS_MAJVER}" != "6" ] && [ ${IDS_MAJVER}" != "1" ]; then
+ ${ECHO} "ERROR: $PROG only works with JES DS version 5.x and 6.x and FDS 1.1.3, not ${IDS_VER}."
exit 1
fi
if [ $DEBUG -eq 1 ]; then
Execute this script and answer a series of questions to create the default profile. You can edit these on the Fedora Directory Server later, or rerun the script as necessary. Questions you want to pay particular attention to are:
  1. Default server list - space separated list of LDAP servers, you may have more than one.
  2. Credential level - can you do user/group searches anonymously or do you need to bind first?
  3. Setup Service Authentication Method - you'll probably want to create a 'pam_ldap' auth method of type 'simple' while you're here.
  4. Setup Service Search Descriptors - you may want to setup search descriptors for different services if your LDAP directory is large.
Once the changes are committed, the script will execute a series of ldapmodify's to create the base structure and default profile. Run an ldapsearch for the newly created profile and sanity check what you've entered. The profile name will change depending on what you answered to the question:

[root@solaris10]$ ldapsearch -h ldap.somedomain.com.au -p 389 -b "cn=default,ou=profile,dc=somedomain,dc=com,dc=au" "objectClass=*"
version: 1
dn: cn=default,ou=profile,dc=somedomain,dc=com,dc=au
credentialLevel: anonymous
defaultServerList: 1.2.3.4 5.6.7.8
authenticationMethod: simple
serviceAuthenticationMethod: pam_ldap:simple
defaultSearchBase: ou=Staff,dc=somedomain,dc=com,dc=au
serviceSearchDescriptor: passwd:ou=Users,dc=somedomain,dc=com,dc=au?sub
serviceSearchDescriptor: shadow:ou=Users,dc=somedomain,dc=com,dc=au?sub
serviceSearchDescriptor: group:ou=Groups,dc=somedomain,dc=com,dc=au?sub
objectClass: top
objectClass: DUAConfigProfile
followReferrals: FALSE
defaultSearchScope: sub
searchTimeLimit: 10
profileTTL: 43200
cn: default
bindTimeLimit: 10
Configure Solaris 10 for LDAP

Once you have a profile you can tell Solaris 10 servers to use this profile to configure themselves for LDAP. The /usr/sbin/ldapclient command does this. It requires only enough information to find the profile, namely the LDAP server, profile name, plus any proxy credentials that are needed to search for the profile (if you can't ldapsearch it anonymously):
ldapclient -v init -a profileName=default -a domainname=somedomain.com.au ldap.somedomain.com.au
Watch the output of this command to make sure it succeeds. If all is good so far you will be able to run /usr/bin/ldaplist group and /usr/bin/ldaplist passwd, as well as id username and groups username, which will all query LDAP.

Fix Domain Name Resolution

The ldapclient command replaces /etc/nsswitch.conf with a very heavy LDAP configuration, which may not be what you're after. I always correct the hosts line in nsswitch.conf as we don't store host information in LDAP, you can remove a lot more if you wish:
hosts:      ldap [NOTFOUND=continue] files dns
PAM authentication with LDAP

With user and group lookups working, you'll want to be able to authenticate as your LDAP users. Here is a sample PAM configuration that adds the pam_ldap module to several services:
#
# Authentication management
#
# login service (explicit because of pam_dial_auth)
#
login auth requisite pam_authtok_get.so.1
login auth required pam_dhkeys.so.1
login auth required pam_unix_cred.so.1
login auth required pam_dial_auth.so.1
login auth binding pam_unix_auth.so.1 server_policy
login auth required pam_ldap.so.1
#
# rlogin service (explicit because of pam_rhost_auth)
#
rlogin auth sufficient pam_rhosts_auth.so.1
rlogin auth requisite pam_authtok_get.so.1
rlogin auth required pam_dhkeys.so.1
rlogin auth required pam_unix_cred.so.1
rlogin auth binding pam_unix_auth.so.1 server_policy
rlogin auth required pam_ldap.so.1
#
# rsh service (explicit because of pam_rhost_auth,
# and pam_unix_auth for meaningful pam_setcred)
#
rsh auth sufficient pam_rhosts_auth.so.1
rsh auth required pam_unix_cred.so.1
rsh auth binding pam_unix_auth.so.1 server_policy
rsh auth required pam_ldap.so.1
#
# PPP service (explicit because of pam_dial_auth)
#
ppp auth requisite pam_authtok_get.so.1
ppp auth required pam_dhkeys.so.1
ppp auth required pam_dial_auth.so.1
ppp auth binding pam_unix_auth.so.1 server_policy
ppp auth required pam_ldap.so.1
#
# Default definitions for Authentication management
# Used when service name is not explicitly mentioned for authentication
#
other auth requisite pam_authtok_get.so.1
other auth required pam_dhkeys.so.1
other auth required pam_unix_cred.so.1
other auth binding pam_unix_auth.so.1 server_policy
other auth required pam_ldap.so.1
#
# passwd command (explicit because of a different authentication module)
#
passwd auth binding pam_passwd_auth.so.1 server_policy
passwd auth required pam_ldap.so.1
#
# cron service (explicit because of non-usage of pam_roles.so.1)
#
cron account required pam_unix_account.so.1
#
# Default definition for Account management
# Used when service name is not explicitly mentioned for account management
#
other account requisite pam_roles.so.1
other account binding pam_unix_account.so.1 server_policy
other account required pam_ldap.so.1
#
# Default definition for Session management
# Used when service name is not explicitly mentioned for session management
#
other session required pam_unix_session.so.1
#
# Default definition for Password management
# Used when service name is not explicitly mentioned for password management
#
other password required pam_dhkeys.so.1
other password requisite pam_authtok_get.so.1
other password requisite pam_authtok_check.so.1
other password required pam_authtok_store.so.1 server_policy
#
# Support for Kerberos V5 authentication and example configurations can
# be found in the pam_krb5(5) man page under the "EXAMPLES" section.
#
Limit Login Access

By default the ldapclient command will have modified the passwd and shadow to use LDAP:
passwd:        files ldap
group: files ldap
This will allow all users with a valid login shell access to the Solaris host, which may not be what you desire. You could limit the scope of the user search in the profile using a service search descriptor like:
serviceSearchDescriptor: passwd:ou=IT,ou=Users,dc=somedomain,dc=com,dc=au?sub
However it's probably more flexible to limit login access through other Solaris means. A very quick way is to put NSS passwd lookups into NIS compatability mode so you can use the old style +/- notations in the passwd file. To avoid any hassles later on, disable nscd from caching anything for us:
svcadm disable svc:/system/name-service-cache:default
Edit /etc/nsswitch.conf and put the passwd file into NIS compatabillity mode:
passwd: files compat
group: files ldap
passwd_compat: ldap
We can then modify /etc/passwd and /etc/shadow to allow and deny users. To add a user, the +username notation is used. You can override any fields in the passwd file, for example you could force everyone's shells to be /bin/sh. The first two lines below in the passwd and shadow files add user1 and user2 without any modifications. The third line adds all users but modifies their shell to something invalid so they cannot log in. You could simply omit the 'all users' include, however there may be situations where you want the UID lookups to occur without allowing everyone to login.
/etc/passwd
...
+user1::::::
+user2::::::
+::::::/usr/bin/false

/etc/shadow
...
+user1::::::::
+user2::::::::
+::::::::
To make sure only the users you really want to log in have valid shells, use getent passwd to list passwd file entries. If you use the 'all users' include above, the same user will be listed multiple times with different shells. Remember that the first username key found is what is used.

Don't forget to re-enable nscsd when you're done:
svcadm enable svc:/system/name-service-cache:default
A better method would be to implement Linux's pam_access.so module instead of using the dated NIS compatability mode, but this module is not in Solaris 10 by default. Hopefully I can find a package for pam_access some time in the near future, otherwise I'll be building it myself.

SSH SOCKS5 tunnel with PuTTY in Windows

First post, very simple, but something that took me longer than I thought it would to find an answer to online. In Linux it's very easy to use ssh to create a SOCKS5 proxy tunnel through your SSH target. You then point a browser at localhost and some arbitrary port you specify, thus masquerading your local browser as the machine you're SSHed into:

ssh -D 12345 username@remotehost.com.au
The same can be done on Windows just as easily with PuTTY. Download it if you haven't already and put a copy in %SYSTEMROOT% (C:\Windows\). In the Run dialog or search box, enter:

putty -D 12345 username@remotehost.com.au
Login to the remote host. Change Firefox's SOCKS proxy setting to be 'localhost' and whatever port you specify (12345) and browse away.