From bd9be2cf0573026424aa068ca8141986e06c2ece Mon Sep 17 00:00:00 2001 From: Aaron Spangler Date: Fri, 13 Feb 2004 02:08:27 +0000 Subject: [PATCH] Merged in LDAP Support --- CHANGES | 2 + Makefile.in | 5 +- README.LDAP | 274 +++++++++++++++++++++++++++++++++++++++++++++++++++ config.h.in | 9 ++ configure.in | 20 ++++ 5 files changed, 308 insertions(+), 2 deletions(-) create mode 100644 README.LDAP diff --git a/CHANGES b/CHANGES index 0f5bce92d..a750be7eb 100644 --- a/CHANGES +++ b/CHANGES @@ -1670,3 +1670,5 @@ Sudo 1.6.7p6 released. be logged as run by the user specified by the SUDO_USER environment variable. In -e mode (sudoedit), SUDO_USER is used to determine what user to run the editor when the real uid is 0. + +524) Merged in LDAP support from Aaron Spangler. diff --git a/Makefile.in b/Makefile.in index 8e06986ee..2b7009925 100644 --- a/Makefile.in +++ b/Makefile.in @@ -118,7 +118,7 @@ PROGS = @PROGS@ SRCS = alloc.c alloca.c check.c closefrom.c def_data.c defaults.c env.c err.c \ fileops.c find_path.c fnmatch.c getcwd.c getprogname.c getspwuid.c \ - goodpath.c interfaces.c lex.yy.c lsearch.c logging.c parse.c parse.lex \ + goodpath.c interfaces.c ldap.c lex.yy.c lsearch.c logging.c parse.c parse.lex \ parse.yacc set_perms.c sigaction.c snprintf.c strcasecmp.c strerror.c \ strlcat.c strlcpy.c sudo.c sudo.tab.c sudo_edit.c testsudoers.c \ tgetpass.c utime.c visudo.c zero_bytes.c $(AUTH_SRCS) @@ -139,7 +139,7 @@ PARSEOBJS = sudo.tab.o lex.yy.o alloc.o defaults.o SUDOBJS = check.o env.o getspwuid.o goodpath.o fileops.o find_path.o \ interfaces.o logging.o parse.o set_perms.o sudo.o sudo_edit.o \ - tgetpass.o zero_bytes.o $(AUTH_OBJS) $(PARSEOBJS) + tgetpass.o zero_bytes.o @SUDO_OBJS@ $(AUTH_OBJS) $(PARSEOBJS) VISUDOBJS = visudo.o fileops.o goodpath.o find_path.o $(PARSEOBJS) @@ -247,6 +247,7 @@ strlcat.o: strlcat.c config.h strlcpy.o: strlcpy.c config.h strerror.o: strerror.c config.h utime.o: utime.c config.h pathnames.h compat.h emul/utime.h +ldap.o: ldap.c $(SUDODEP) parse.h # Authentication functions live in "auth" dir and so need extra care sudo_auth.o: $(authdir)/sudo_auth.c $(AUTHDEP) $(INSDEP) diff --git a/README.LDAP b/README.LDAP new file mode 100644 index 000000000..8e83b8f11 --- /dev/null +++ b/README.LDAP @@ -0,0 +1,274 @@ +This file explains how to use the optional LDAP functionality of SUDO to +store /etc/sudoers information. This feature is separate from LDAP passwords. + +LDAP philosophy +=============== +As times change and servers become cheap, an enterprise can easily have 500+ +UNIX servers. Using LDAP to synchronize Users, Groups, Hosts, Mounts, and +others across an enterprise can greatly reduce the administrative overhead. + +Sudo in the past has only used a single local configuration file /etc/sudoers. +Some have attempted to workaround this by synchronizing changes via +RCS/CVS/RSYNC/RDIST/RCP/SCP and even NFS. Many have asked for a Hesiod, NIS, +or LDAP patch for sudo, so here is my attempt at LDAP'izing sudo. + +Definitions +=========== +Many times the word 'Directory' is used in the document to refer to the LDAP +server, structure and contents. + +Many times 'options' are used in this document to refer to sudoer 'defaults'. +They are on in the same. + +Design Features +=============== + + * Sudo no longer needs to read all sudoers. Parsing of /etc/sudoers requires + the entire file to be read. The LDAP feature of sudo uses two + (sometimes three) LDAP queries per invocation. It never reads the + all the sudoer entries in the LDAP store. This makes it + especially fast and particularly usable in LDAP environments. + The first query is to parse default options (see below). The second + is to match against the username or groups a user belongs to. + (The special ALL tag is matched in this query too.) + If not match is against the username, the third query pulls the entries + that match against user netgroups to compare back to the user. + + * Sudo no longer blows up if there is a typo. Parsing of /etc/sudoers can + still blow up when sudo is invoked. However when using the LDAP feature + of sudo, LDAP syntax rules are applied before the data is uploaded into + the LDAP server, so proper syntax is always guaranteed! + One can of course still insert a bogus hostname or username, + but sudo will not care. + + * Options inside of entries now override global default options. + /etc/sudoers allowed for only default options and limited options + associated with user/host/command aliases. The syntax can be difficult + for the newbie. The LDAP feature attempts to simplify this and yet + still provide maximum flexibility. + + Sudo first looks for an entry called 'cn=default' in the SUDOers + container. If found, the multi-valued sudoOption attribute is parsed + the same way the global 'Defaults' line in /etc/sudoers is parsed. + + If on the second or third query, a response containing a sudoRole + which matches against the user, host, and command, then the matched + object is scanned for a additional options to override the top-level + defaults. See the Example LDAP content below for more information. + + * Visudo is no longer needed. Visudo provides locking and syntax checking + against the /etc/sudoers file. Since LDAP updates are atomic, locking + is no longer necessary. Because syntax is checked when the data is + inserted into LDAP, the sudoers syntax check becomes unnecessary. + + * Aliases are no longer needed. User, Host, and Command Aliases were setup + to allow simplification and readability of the sudoers files. Since the + LDAP sudoer entry allows multiple values for each of its attributes and + since most LDAP browsers are graphical and easy to work with, original + aliases are no longer needed. + + If you want to specify lots of users into an entry or want to have + similar entries with identical users, then use either groups or user + netgroups. Thats what groups and netgroups are for and Sudo handles + this well. Or just paste them all into the LDAP record. + + If you want to specify lots of hosts into an entry, use netgroups or + IP address matches (10.2.3.4/255.255.0.0). Thats what netgroups are + for and Sudo handles this well. Or just past them all into the LDAP + record. + + If you want to specify lots of commands, use directories or wildcards, + or just paste them all into LDAP. That's what it's for. + + * The /etc/sudoers file can be disabled. Paranoid security administrators + can now disallow parsing of any local /etc/sudoers file by an LDAP + sudoOption '!local_sudoers'. This way all sudoers can be controlled + and audited in one place because local entries are not allowed. + In the future, this file may not be present. + BUG: THIS OPTION IS NOT IMPLEMENTED YET. + + * The sudo binary compiled with LDAP support should be totally + backward compatible and be syntactically and source code equivalent + to its non LDAP-enabled build. + + +Build instructions +================== +The most simplest way to build sudo with LDAP support is to include the +'--with-ldap' option. I recommend including the '--with-pam' option on those +system with PAM so that if you decide to use LDAP for authentication, you won't +need to recompile sudo. + + $ ./configure --with-ldap --with-pam + +If your ldap libraries and headers are in a non standard place, you will need +to specify them at configure time. + + $ CPPFLAGS="-I/usr/local/ldapsdk/include" \ + > LDFLAGS="-L/usr/local/ldapsdk/lib" \ + > ./configure --with-ldap --with-pam + +In early revs of sudo where the '--with-ldap' option is not available, you +need to manually append '#define HAVE_LDAP 1' to config.h and set +LIBS='-lldap' in Makefile. + +Sudo by default builds against OpenLDAP's libraries. For others LDAP +libraries such as Netscape, iPlanet, Mozilla, SecureWay, add these lines +to config.h before running make: + + #undef HAVE_LDAP_INITIALIZE + #define HAVE_LBER_H + +You might have to also include '-llber' or '-lldif' in your LIBS. + +Your Mileage may vary. Please let Aaron Spangler +know what combinations worked best for your OS & LDAP Combinations so +we can improve sudo. + +Schema Changes +============== +Add the following schema to your LDAP server so that it may contain sudoer +content. In OpenLDAP, simply place this into a new file and 'include' it +in your slapd.conf and restart slapd. For other LDAP servers, provide this +to your LDAP Administrator. Make sure to index the attribute 'sudoUser'. + + + # + # schema file for sudo + # + + attributetype ( 1.3.6.1.4.1.15953.9.1.1 + NAME 'sudoUser' + DESC 'User(s) who may run sudo' + EQUALITY caseExactIA5Match + SUBSTR caseExactIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + + attributetype ( 1.3.6.1.4.1.15953.9.1.2 + NAME 'sudoHost' + DESC 'Host(s) who may run sudo' + EQUALITY caseExactIA5Match + SUBSTR caseExactIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + + attributetype ( 1.3.6.1.4.1.15953.9.1.3 + NAME 'sudoCommand' + DESC 'Command(s) to be executed by sudo' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + + attributetype ( 1.3.6.1.4.1.15953.9.1.4 + NAME 'sudoRunAs' + DESC 'User(s) impersonated by sudo' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + + attributetype ( 1.3.6.1.4.1.15953.9.1.5 + NAME 'sudoOption' + DESC 'Options(s) followed by sudo' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + + objectclass ( 1.3.6.1.4.1.15953.9.2.1 NAME 'sudoRole' SUP top STRUCTURAL + DESC 'Sudoer Entries' + MUST ( cn ) + MAY ( sudoUser $ sudoHost $ sudoCommand $ sudoRunAs $ sudoOption $ + description ) + ) + + +Importing /etc/sudoers to LDAP +============================== +Importing is a two step process. + +Step 1: +Ask your LDAP Administrator where to create the ou=SUDOers container. +(An example location is shown below). Then use the provided script to convert +your sudoers file into LDIF format. The script will also convert any default +options. + + # SUDOERS_BASE=ou=SUDOers,dc=example,dc=com + # export SUDOERS_BASE + # ./sudoers2ldif /etc/sudoers > /tmp/sudoers.ldif + +Step 2: +Import into your directory server. If you are using OpenLDAP, do the following +if you are using another directory, provide the LDIF file to your LDAP +Administrator. An example is shown below. + + # ldapadd -f /tmp/sudoers.ldif -h ldapserver \ + > -D cn=Manager,dc=example,dc=com -W -x + +Example sudoers Entries in LDAP +=============================== +The equivalent of a sudoer in LDAP is a 'sudoRole'. It contains sudoUser(s), +sudoHost, sudoCommand and optional sudoOption(s) and sudoRunAs(s). + + +Managing LDAP entries +===================== +Doing a one-time bulk load of your ldap entries is fine. However what if you +need to make minor changes on a daily basis? It doesn't make sense to delete +and re-add objects. (You can, but this is tedious). + +I recommend using any of the following LDAP browsers to administer your SUDOers. + * GQ - The gentleman's LDAP client - Open Source - I use this a lot on + Linux and since it is Schema aware, I don't need to create a sudoRole + template. + http://biot.com/gq/ + + * LDAP Browser/Editor - by Jarek Gawor - I use this a lot on Windows + and Solaris. It runs anywhere in a Java Virtual Machine including + web pages. You have to make a template from an existing sudoRole entry. + http://www.iit.edu/~gawojar/ldap + http://www.mcs.anl.gov/~gawor/ldap + http://ldapmanager.com + + There are dozens of others, some open source, some free, some not. + + +Configure your /etc/ldap.conf +============================= +The /etc/ldap.conf file is meant to be shared between sudo, pam_ldap, nss_ldap +and other ldap applications and modules. IBM Secureway unfortunately uses +the same filename but has a different syntax. If you need to rename where +this file is stored, recompile SUDO with the -DLDAP_CONFIG compile option. + +Make sure you sudoers_base matches exactly with the location you specified +when you imported the sudoers. Below is an example /etc/ldap.conf + + # Either specify a uri or host & port + #host ldapserver + #port 389 + uri ldap://ldapserver + # + # must be set or sudo will ignore LDAP + sudoers_base ou=SUDOers,dc=example,dc=com + # + # verbose sudoers matching from ldap + #sudoers_debug 2 + # + # optional proxy credentials + #binddn + #bindpw + # + # LDAP Protocol Version defaults to 3 + #ldap_version 3 + # + +Debugging your LDAP configuration +================================= +Enable debugging if you think sudo is not parsing LDAP the way you think it +it should. A value of 1 shows moderate debugging. A value of 2 shows the +results of the matches themselves. Make sure to set the value back to zero +so that other users don't get confused by the debugging messages. This value +is 'sudoers_debug' in the /etc/ldap.conf. + +Configure your /etc/nsswitch.conf +================================= +At the time of this writing, sudo does not consult nsswitch.conf for the +search order. But if it did, it would look like this: +This might be implemented in the future. For now just skip this step. + + sudoers: files ldap + diff --git a/config.h.in b/config.h.in index e0ce34d04..66628c04b 100644 --- a/config.h.in +++ b/config.h.in @@ -162,6 +162,15 @@ /* Define if you use Kerberos V. */ #undef HAVE_KERB5 +/* Define if you use LDAP. */ +#undef HAVE_LDAP + +/* Define if your LDAP needs . (OpenLDAP does not) */ +#undef HAVE_LBER_H + +/* Define if your LDAP Supports URLs. (OpenLDAP does) */ +#define HAVE_LDAP_INITIALIZE + /* Define to 1 if you have the `lockf' function. */ #undef HAVE_LOCKF diff --git a/configure.in b/configure.in index 5619c6ac7..9c3ee5ab4 100644 --- a/configure.in +++ b/configure.in @@ -19,6 +19,7 @@ AC_SUBST(PROGS)dnl AC_SUBST(CPPFLAGS)dnl AC_SUBST(LDFLAGS)dnl AC_SUBST(SUDO_LDFLAGS)dnl +AC_SUBST(SUDO_OBJS)dnl AC_SUBST(LIBS)dnl AC_SUBST(SUDO_LIBS)dnl AC_SUBST(NET_LIBS)dnl @@ -906,6 +907,17 @@ AC_ARG_WITH(goons-insults, [ --with-goons-insults include the insults from t ;; esac]) +AC_ARG_WITH(ldap, [ --with-ldap enable LDAP support], +[case $with_ldap in + yes) AC_DEFINE(HAVE_LDAP, 1, [Define if you use LDAP.]) + AC_MSG_CHECKING(whether to use sudoers from LDAP) + AC_MSG_RESULT(yes) + ;; + no) ;; + *) AC_MSG_ERROR(["--with-ldap does not take an argument."]) + ;; +esac]) + AC_ARG_WITH(pc-insults, [ --with-pc-insults replace politically incorrect insults with less offensive ones], [case $with_pc_insults in yes) AC_DEFINE(PC_INSULTS, 1, [Define to replace politically incorrect insults with less offensive ones.]) @@ -2064,6 +2076,14 @@ if test "$with_authenticate" = "yes"; then SUDO_LIBS="${SUDO_LIBS} -ls" fi +dnl +dnl extra lib and .o file for LDAP support +dnl +if test "$with_ldap" = "yes"; then + SUDO_LIBS="${SUDO_LIBS} -lldap" + SUDO_OBJS="${SUDO_OBJS} ldap.o" +fi + dnl dnl Add $blibpath to SUDO_LDFLAGS if specified by the user or if we dnl added -L dirpaths to SUDO_LDFLAGS. -- 2.50.1