I have been spending a bit of time lately configuring Solaris and Linux hosts to authenticate against LDAP. Authentication works well on the surface, but the actual client implementations are somewhat lacking. Let’s take the Linux pam_ldap module for instance. To authenticate a single session, the pam_ldap module performs thirty-three operations, which includes 7 TCP connections and a number of redundant searches. Here is what I see in my logfile for each login session that is authenticated through pam_ldap:

1. New connection
  conn=801
  LDAP connection from 10.10.20.3 to 10.10.20.2

2. Anonymous BIND
  conn=801
  BIND dn="" method=128 version=3

3. Search
   conn=801
   SRCH base="ou=people,dc=prefetch,dc=net"
   FILTER="(&(objectClass=posixAccount)(uid=test))"
   ATTRIBUTES="uid userPassword uidNumber gidNumber cn homeDirectory
              loginShell gecos description objectClass"
   nentries => 1

4. New connection
   conn=802
    LDAP connection from 10.10.20.3 to 10.10.20.2

5. Anonymous BIND
   conn=802
   BIND dn="" method=128 version=3

6. Search
   conn=802
   SRCH base="ou=people,dc=prefetch,dc=net"
   FILTER="(&(objectClass=posixAccount)(objectClass=posixAccount)(uid=test))"
   ATTRIBUTES=ALL
   nentries => 1

7. BIND as user
   conn=802
   BIND dn="uid=test,ou=People,dc=prefetch,dc=net" method=128 version=3

8. Anonymous BIND
   conn=802
   BIND dn="" method=128 version=3

9. Close connection 801

10. New connection
    conn=803
    LDAP connection from 10.10.20.3 to 10.10.20.2

11. Anonymous BIND
    conn=803
    BIND dn="" method=128 version=3

12. Search
    conn=803
    SRCH base="ou=people,dc=prefetch,dc=net"
    FILTER="(&(objectClass=posixAccount)(uid=test))"
    ATTRIBUTES=ALL
    nentries => 1

13. Search
    conn=803
    SRCH base="ou=people,dc=prefetch,dc=net"
    FILTER="(&(objectClass=posixGroup)(|(memberUid=test)
           (uniqueMember=uid=test,ou=People,dc=prefetch,dc=net)))"
    attrs="gidNumber"
    nentries => 0

14. Close connection 802

15. New connection
    conn=804
    LDAP connection from 10.10.20.3 to 10.10.20.2

16. Anonymous BIND
    conn=804
    BIND dn="" method=128 version=3

17. Search
    conn=804
    SRCH base="ou=people,dc=prefetch,dc=net"
    FILTER="(&(objectClass=posixAccount)(uidNumber=100))"
    ATTRIBUTES="uid userPassword uidNumber gidNumber cn homeDirectory
               loginShell gecos description objectClass"
    nentries => 1

18. Search
    conn=804
    SRCH base="ou=people,dc=prefetch,dc=net"
    FILTER="(&(objectClass=posixAccount)(uid=test))"
    ATTRIBUTES="uid userPassword uidNumber gidNumber cn homeDirectory
               loginShell gecos description objectClass"
    nentries => 1

19. New connection
    conn=805
    LDAP connection from 10.10.20.3 to 10.10.20.2

20. Anonymous BIND
    conn=805
    BIND dn="" method=128 version=3

21. Search
    conn=805
    SRCH base="ou=people,dc=prefetch,dc=net"
    FILTER="(&(objectClass=posixAccount)(uidNumber=100))"
    ATTRIBUTES="uid userPassword uidNumber gidNumber cn homeDirectory
               loginShell gecos description objectClass"
    nentries => 1

22. New connection
    conn=806
    LDAP connection from 10.10.20.3 to 10.10.20.2

23. Anonymous BIND
    conn=806
    BIND dn="" method=128 version=3

24. Search
    conn=806
    SRCH base="ou=people,dc=prefetch,dc=net"
    FILTER="(&(objectClass=posixAccount)(uidNumber=100))"
    ATTRIBUTES="uid userPassword uidNumber gidNumber cn homeDirectory
               loginShell gecos description objectClass"
    nentries => 1

25. Close connection 806

26. New connection
    conn=807
    LDAP connection from 10.10.20.3 to 10.10.20.2

27. Anonymous BIND
    conn=807
    BIND dn="" method=128 version=3

28. Search
    conn=807
    SRCH base="ou=people,dc=prefetch,dc=net"
    FILTER="(&(objectClass=posixAccount)(uidNumber=100))"
    ATTRIBUTES="uid userPassword uidNumber gidNumber cn homeDirectory
               loginShell gecos description objectClass"
    nentries => 1

29. Close connection 807

30. Close connection 805

31. Search
    conn=804
    SRCH base="ou=people,dc=prefetch,dc=net"
    FILTER="(&(objectClass=posixAccount)(uid=test))"
    ATTRIBUTES="uid userPassword uidNumber gidNumber cn homeDirectory
               loginShell gecos description objectClass"
    nentries => 1

32. Close connection 803

33. Close connection 804

The Sun native LDAP client is not much better, and I am somewhat curious why the PAM modules couldn’t be written to use persistent connections, and to cache data between PAM phases. If you are using either of these implementations to authenticate users, I sure hope you’re using the name service caching daemon (nscd). :)

Posted by matty, filed under Linux Security, Solaris Security. Date: May 21, 2007, 6:45 pm | 3 Comments »

Most modern day UNIX operating systems store password expiration data in /etc/shadow. This expiration data includes the last time a user changed their password, the number of days a user can use a given password, an interval to warn a user that their password is going to expire, etc. There are six (I don’t count sp_flag since it’s reserved for future use) fields that apply to password expiration, and they are described in the shadow(3) manual page:

Field 3: sp_lstchg - days since Jan 1, 1970 password was last changed.
Field 4: sp_min - days before which password may not be changed.
Field 5: sp_max - days after which password must be changed.
Field 6: sp_warn - days before password is to expire that  user  is  warned  of pending password e xpiration.
Field 7: sp_inact  -  days  after  password  expires that account is considered inactive and disabled.
Field 8: sp_expire - days since Jan 1, 1970 when account will be disabled.

If you are looking for a nifty tool to help visualize this data, you can check out the super useful chage utility.

Posted by matty, filed under Linux Security. Date: January 21, 2007, 11:36 am | No Comments »

To ensure that my CentOS machines run as efficiently and securely as possible, I disable a number of services after each installation. The end result is a system that accepts ssh connections on TCP port 22, and on one or more service ports that are in use by the applications hosted on the platform. To get to this state, I go through and disable numerous services that come enabled by default. Here is the default list of services that are enabled after a CentOS 4.4 installation:

$ chkconfig –list | grep on

atd             0:off   1:off   2:off   3:on    4:on    5:on    6:off
messagebus      0:off   1:off   2:off   3:on    4:on    5:on    6:off
smartd          0:off   1:off   2:on    3:on    4:on    5:on    6:off
portmap         0:off   1:off   2:off   3:on    4:on    5:on    6:off
sendmail        0:off   1:off   2:on    3:on    4:on    5:on    6:off
netfs           0:off   1:off   2:off   3:on    4:on    5:on    6:off
cups            0:off   1:off   2:on    3:on    4:on    5:on    6:off
irqbalance      0:off   1:off   2:off   3:on    4:on    5:on    6:off
rpcgssd         0:off   1:off   2:off   3:on    4:on    5:on    6:off
xfs             0:off   1:off   2:on    3:on    4:on    5:on    6:off
isdn            0:off   1:off   2:on    3:on    4:on    5:on    6:off
autofs          0:off   1:off   2:off   3:on    4:on    5:on    6:off
gpm             0:off   1:off   2:on    3:on    4:on    5:on    6:off
apmd            0:off   1:off   2:on    3:on    4:on    5:on    6:off
crond           0:off   1:off   2:on    3:on    4:on    5:on    6:off
acpid           0:off   1:off   2:off   3:on    4:on    5:on    6:off
microcode_ctl   0:off   1:off   2:on    3:on    4:on    5:on    6:off
pcmcia          0:off   1:off   2:on    3:on    4:on    5:on    6:off
cpuspeed        0:off   1:on    2:on    3:on    4:on    5:on    6:off
xinetd          0:off   1:off   2:off   3:on    4:on    5:on    6:off
rpcidmapd       0:off   1:off   2:off   3:on    4:on    5:on    6:off
readahead_early 0:off   1:off   2:off   3:off   4:off   5:on    6:off
readahead       0:off   1:off   2:off   3:off   4:off   5:on    6:off
sshd            0:off   1:off   2:on    3:on    4:on    5:on    6:off
anacron         0:off   1:off   2:on    3:on    4:on    5:on    6:off
network         0:off   1:off   2:on    3:on    4:on    5:on    6:off
kudzu           0:off   1:off   2:off   3:on    4:on    5:on    6:off
syslog          0:off   1:off   2:on    3:on    4:on    5:on    6:off
nfslock         0:off   1:off   2:off   3:on    4:on    5:on    6:off
rawdevices      0:off   1:off   2:off   3:on    4:on    5:on    6:off
mdmonitor       0:off   1:off   2:on    3:on    4:on    5:on    6:off
haldaemon       0:off   1:off   2:off   3:on    4:on    5:on    6:off

Several of these services are required, but several others serve no purpose in my environment, and use CPU and memory resources that would be better allocated to my applications. Since I don’t use RPC services, autofs or NFS, those are the first to get disabled:

$ /sbin/chkconfig –level 0123456 portmap off
$ /sbin/chkconfig –level 0123456 nfslock off
$ /sbin/chkconfig –level 0123456 netfs off
$ /sbin/chkconfig –level 0123456 rpcgssd off
$ /sbin/chkconfig –level 0123456 rpcidmapd off
$ /sbin/chkconfig –level 0123456 autofs off

I also don’t allow individual hosts to receive mail from the outside world, so sendmail gets nixed next:

$ /sbin/chkconfig –level 0123456 sendmail off

On server platforms, who needs printing?:

$ /sbin/chkconfig –level 0123456 cups off

Now we get to the font server, isdn capabilities, console mouse and pcmcia support. I don’t use these services on my servers, so they get disabled as well:

$ /sbin/chkconfig –level 0123456 xfs off
$ /sbin/chkconfig –level 0123456 isdn off
$ /sbin/chkconfig –level 0123456 gpm off
$ /sbin/chkconfig –level 0123456 pcmcia off

Once these services are disabled (and optionally stopped with the service command or a reboot), my netstat output looks nice and clean:

$ netstat –tcp –udp –listening

Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address               Foreign Address             State
tcp        0      0 *:ssh                       *:*                         LISTEN

This has served me well over the years, since it reduces boot time (less rc scripts to run), and frees up additional resources for my applications (while this isn’t substantial, every page of memory helps!).

Posted by matty, filed under Linux Security. Date: December 27, 2006, 12:28 pm | 2 Comments »

I often forget about the Centos Linux chage utility, and it’s ability to manage the expiration data in /etc/shadow. In addition to being able to manage password policies, chage can be be run with the “-l” option to view the policy set for a user, and the date when a users password was last changed:

$ chage -l matty

Minimum:        0
Maximum:        99999
Warning:        7
Inactive:       -1
Last Change:            Dec 25, 2006
Password Expires:       Never
Password Inactive:      Never
Account Expires:        Never

If you have a security organization, ‘chage -l’ is a great command to allow them to run through sudo.

Posted by matty, filed under Linux Security. Date: December 24, 2006, 12:31 pm | 2 Comments »

I needed to setup password policies on a few CentOS 4.4 machines last week. The password policy needed to define the minimum length of a password, the number of days a password is valid, the strength of a password, and a warning period to alert individuals that their password is about to expire. Expiration data for each user is stored in their entry in /etc/shadow, and is initially populated based on the password policies in /etc/logins.defs. Here is a list of password policies that I typically set in /etc/logins.defs:

# Password aging controls:
#
#       PASS_MAX_DAYS   Maximum number of days a password may be used.
#       PASS_MIN_DAYS   Minimum number of days allowed between password changes.
#       PASS_MIN_LEN    Minimum acceptable password length.
#       PASS_WARN_AGE   Number of days warning given before a password expires.
#
PASS_MAX_DAYS   60
PASS_MIN_DAYS   0
PASS_MIN_LEN    8
PASS_WARN_AGE   10

For accounts that were created without a password policy, the chage command can be used to create one. To enforce strong passwords, you need to add the pam module pam_cracklib.so to the password management group in /etc/pam.conf (or the applicable service definition in /etc/pam.d). Managing passwords is a pain, but it is one of the most important tasks in securing any server platform.

Posted by matty, filed under Linux Security. Date: December 24, 2006, 12:22 pm | No Comments »