This patch will upgrade Sudo version 1.6.9 patchlevel 9 to Sudo
version 1.6.9 patchlevel 10.  To apply:

    $ cd sudo-1.6.9p9
    $ patch -p1 < sudo-1.6.9p10.patch

diff -ur sudo-1.6.9p9/CHANGES sudo-1.6.9p10/CHANGES
--- sudo-1.6.9p9/CHANGES	Sun Dec  2 12:14:43 2007
+++ sudo-1.6.9p10/CHANGES	Wed Dec 19 14:30:55 2007
@@ -2006,3 +2006,12 @@
      to be used in all cases.  Also set when the -p flag is used.
 
 Sudo 1.6.9p9 released.
+
+634) Moved LDAP options into a table for simplified parsing/setting.
+
+635) Fixed a problem with how some LDAP options were being applied.
+
+636) Added support for connecting directly to LDAP servers via SSL
+     in addition to the existing start_tls support.
+
+Sudo 1.6.9p10 released.
diff -ur sudo-1.6.9p9/Makefile.in sudo-1.6.9p10/Makefile.in
--- sudo-1.6.9p9/Makefile.in	Mon Dec  3 05:34:32 2007
+++ sudo-1.6.9p10/Makefile.in	Mon Dec 17 14:18:14 2007
@@ -20,7 +20,7 @@
 #
 # @configure_input@
 #
-# $Sudo: Makefile.in,v 1.246.2.20 2007/12/03 10:34:32 millert Exp $
+# $Sudo: Makefile.in,v 1.246.2.21 2007/12/17 19:18:14 millert Exp $
 #
 
 #### Start of system configuration section. ####
@@ -131,7 +131,7 @@
 
 LIBOBJS = @LIBOBJS@ @ALLOCA@
 
-VERSION = 1.6.9p9
+VERSION = 1.6.9p10
 
 DISTFILES = $(SRCS) $(HDRS) BUGS CHANGES HISTORY INSTALL INSTALL.configure \
             LICENSE Makefile.in PORTING README README.LDAP \
diff -ur sudo-1.6.9p9/README.LDAP sudo-1.6.9p10/README.LDAP
--- sudo-1.6.9p9/README.LDAP	Mon Jul 16 22:42:25 2007
+++ sudo-1.6.9p10/README.LDAP	Wed Dec 19 16:37:35 2007
@@ -124,7 +124,8 @@
 restart slapd.  For other LDAP servers, provide this to your LDAP
 Administrator.  Make sure to index the attribute 'sudoUser'.
 
-For the SunONE or iPlanet LDAP server, use the schema.iPlanet file.
+For netscape-derived LDAP servers such as SunONE, iPlanet or Fedora
+Directory, use the schema.iPlanet file.
 
 Importing /etc/sudoers to LDAP
 ==============================
@@ -160,8 +161,18 @@
 ===============================
 The equivalent of a sudoer in LDAP is a 'sudoRole'.  It contains sudoUser(s),
 sudoHost, sudoCommand and optional sudoOption(s) and sudoRunAs(s).
-<put an example here>
 
+The following example allows users in group wheel to run any
+command on any host through sudo:
+
+dn: cn=%wheel,ou=SUDOers,dc=example,dc=com
+objectClass: top
+objectClass: sudoRole
+cn: %wheel
+sudoUser: %wheel
+sudoHost: ALL
+sudoCommand: ALL
+
 Managing LDAP entries
 =====================
 Doing a one-time bulk load of your ldap entries is fine.  However what if you
@@ -180,26 +191,32 @@
 	http://www.mcs.anl.gov/~gawor/ldap
 	http://ldapmanager.com
 
-  There are dozens of others, some open source, some free, some not.
+  * Apache Directory Studio - Open Source - an Eclipse-based LDAP
+    development platform.  Includes an LDAP browser, and LDIF editor,
+    a schema editor and more.
+    http://directory.apache.org/studio
 
+  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.
+this file is stored, re-run configure with the --with-ldap-conf-file=filename
+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
+  # Either specify a URI or host and port.
+  # If neither is specified sudo will default to localhost port 389.
   #host          ldapserver
   #port          389
   #
-  # URI will override host & port settings
-  # but only works with LDAP SDK's that support
-  # ldap_initialize() such as OpenLDAP
+  # URI will override host & port settings but only works with LDAP
+  # SDK's that support ldap_initialize() such as OpenLDAP.
   uri            ldap://ldapserver
   #uri            ldaps://secureldapserver
   #
@@ -214,21 +231,27 @@
   #bindpw        <password>
   #rootbinddn    <who to search as, uses /etc/ldap.passwd for bindpw>
   #
-  # LDAP Protocol Version defaults to 3
+  # LDAP protocol version, defaults to 3
   #ldap_version 3
   #
+  # Define if you want to use an encrypted LDAP connection.
+  # Typically, you must also set the port to 636 (ldaps).
+  #ssl on
+  #
   # Define if you want to use port 389 and switch to
-  # encryption before the bind credentials are sent
+  # encryption before the bind credentials are sent.
+  # Only supported by LDAP servers that support the start_tls
+  # extension such as OpenLDAP.
   #ssl start_tls
   #
-  # Additional TLS options follow that allow tweaking
-  # of the SSL/TLS connection
+  # Additional TLS options follow that allow tweaking of the
+  # SSL/TLS connection.  Only supported when using OpenLDAP.
   #
   #tls_checkpeer yes # verify server SSL certificate
   #tls_checkpeer no  # ignore server SSL certificate
   #
   # If you enable tls_checkpeer, specify either tls_cacertfile
-  # or tls_cacertdir.
+  # or tls_cacertdir.  Only supported when using OpenLDAP.
   #
   #tls_cacertfile /etc/certs/trusted_signers.pem
   #tls_cacertdir  /etc/certs
@@ -236,11 +259,13 @@
   # For systems that don't have /dev/random
   # use this along with PRNGD or EGD.pl to seed the
   # random number pool to generate cryptographic session keys.
+  # Only supported when using OpenLDAP.
   #
   #tls_randfile /etc/egd-pool
   #
   # You may restrict which ciphers are used.  Consult your SSL
   # documentation for which options go here.
+  # Only supported when using OpenLDAP.
   #
   #tls_ciphers <cipher-list>
   #
@@ -251,9 +276,16 @@
   #   * Do not password protect the key file.
   #   * Ensure the keyfile is only readable by root.
   #
+  # For OpenLDAP:
   #tls_cert /etc/certs/client_cert.pem
   #tls_key  /etc/certs/client_key.pem
   #
+  # For SunONE or iPlanet LDAP, the file specified by tls_cert may
+  # contain CA certs and/or the client's cert.  If the client's
+  # cert is included, tls_key should be specified as well.
+  # For backward compatibility, sslpath may be used in place of tls_cert.
+  #tls_cert /var/ldap/cert7.db
+  #tls_key /var/ldap/key3.db
 
 Debugging your LDAP configuration
 =================================
@@ -321,12 +353,3 @@
   # rather, matches all hosts including web01
   sudoHost: ALL
   sudoHost: !web01
-
-
-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 -ur sudo-1.6.9p9/config.h.in sudo-1.6.9p10/config.h.in
--- sudo-1.6.9p9/config.h.in	Sat Dec  1 10:00:05 2007
+++ sudo-1.6.9p10/config.h.in	Wed Dec 19 13:12:36 2007
@@ -224,6 +224,9 @@
 /* Define to 1 if you have the `ldap_start_tls_s' function. */
 #undef HAVE_LDAP_START_TLS_S
 
+/* Define to 1 if you have the `ldapssl_init' function. */
+#undef HAVE_LDAPSSL_INIT
+
 /* Define to 1 if you have the `lockf' function. */
 #undef HAVE_LOCKF
 
diff -ur sudo-1.6.9p9/configure sudo-1.6.9p10/configure
--- sudo-1.6.9p9/configure	Sat Dec  1 16:52:30 2007
+++ sudo-1.6.9p10/configure	Wed Dec 19 10:42:43 2007
@@ -1562,7 +1562,7 @@
   --with-goons-insults    include the insults from the "Goon Show"
   --with-ldap[=DIR]       enable LDAP support
   --with-ldap-conf-file   path to LDAP configuration file
-  --with-ldap-secret-file path to LDAP secret pasdword file
+  --with-ldap-secret-file path to LDAP secret password file
   --with-pc-insults       replace politically incorrect insults with less offensive ones
   --with-secure-path      override the user's path with a built-in one
   --without-interfaces    don't try to read the ip addr of ether interfaces
@@ -21059,10 +21059,68 @@
 	    { echo "$as_me:$LINENO: result: no" >&5
 echo "${ECHO_T}no" >&6; }
 	    SUDO_LIBS="${SUDO_LIBS} -lkrb5 -lk5crypto -lcom_err"
+	    { echo "$as_me:$LINENO: checking for main in -lkrb5support" >&5
+echo $ECHO_N "checking for main in -lkrb5support... $ECHO_C" >&6; }
+if test "${ac_cv_lib_krb5support_main+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lkrb5support  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
 
 
+int
+main ()
+{
+return main ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_krb5support_main=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_cv_lib_krb5support_main=no
 fi
 
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_krb5support_main" >&5
+echo "${ECHO_T}$ac_cv_lib_krb5support_main" >&6; }
+if test $ac_cv_lib_krb5support_main = yes; then
+  SUDO_LIBS="${SUDO_LIBS} -lkrb5support,"
+fi
+
+
+fi
+
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
     AUTH_OBJS="$AUTH_OBJS kerb5.o"
     _LIBS="$LIBS"
@@ -22378,7 +22436,8 @@
 
 
 
-for ac_func in ldap_initialize ldap_start_tls_s
+
+for ac_func in ldap_initialize ldap_start_tls_s ldapssl_init
 do
 as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
 { echo "$as_me:$LINENO: checking for $ac_func" >&5
diff -ur sudo-1.6.9p9/configure.in sudo-1.6.9p10/configure.in
--- sudo-1.6.9p9/configure.in	Sat Dec  1 19:35:20 2007
+++ sudo-1.6.9p10/configure.in	Wed Dec 19 14:29:29 2007
@@ -1,6 +1,6 @@
 dnl
 dnl Process this file with GNU autoconf to produce a configure script.
-dnl $Sudo: configure.in,v 1.413.2.30 2007/12/02 00:35:20 millert Exp $
+dnl $Sudo: configure.in,v 1.413.2.34 2007/12/19 19:29:29 millert Exp $
 dnl
 dnl Copyright (c) 1994-1996,1998-2007 Todd C. Miller <Todd.Miller@courtesan.com>
 dnl
@@ -909,7 +909,7 @@
 esac])
 AC_ARG_WITH(ldap-conf-file, [  --with-ldap-conf-file   path to LDAP configuration file],
 [AC_DEFINE_UNQUOTED(_PATH_LDAP_CONF, "$with_ldap_conf_file", [Path to the ldap.conf file])])
-AC_ARG_WITH(ldap-secret-file, [  --with-ldap-secret-file path to LDAP secret pasdword file],
+AC_ARG_WITH(ldap-secret-file, [  --with-ldap-secret-file path to LDAP secret password file],
 [AC_DEFINE_UNQUOTED(_PATH_LDAP_SECRET, "$with_ldap_secret_file", [Path to the ldap.secret file])])
 
 AC_ARG_WITH(pc-insults, [  --with-pc-insults       replace politically incorrect insults with less offensive ones],
@@ -2064,7 +2064,7 @@
 	], [
 	    AC_MSG_RESULT(no)
 	    SUDO_LIBS="${SUDO_LIBS} -lkrb5 -lk5crypto -lcom_err"
-	
+	    AC_CHECK_LIB(krb5support, main, [SUDO_LIBS="${SUDO_LIBS} -lkrb5support,"])
     ])
     AUTH_OBJS="$AUTH_OBJS kerb5.o"
     _LIBS="$LIBS"
@@ -2284,7 +2284,7 @@
     AC_MSG_RESULT([yes])
     AC_DEFINE(HAVE_LBER_H)])
 
-    AC_CHECK_FUNCS(ldap_initialize ldap_start_tls_s)
+    AC_CHECK_FUNCS(ldap_initialize ldap_start_tls_s ldapssl_init)
 
     SUDO_LIBS="${SUDO_LIBS}${LDAP_LIBS}"
     LIBS="$_LIBS"
diff -ur sudo-1.6.9p9/ldap.c sudo-1.6.9p10/ldap.c
--- sudo-1.6.9p9/ldap.c	Tue Nov 27 12:06:54 2007
+++ sudo-1.6.9p10/ldap.c	Wed Dec 19 14:29:32 2007
@@ -65,7 +65,7 @@
 #include "parse.h"
 
 #ifndef lint
-__unused static const char rcsid[] = "$Sudo: ldap.c,v 1.11.2.20 2007/11/27 17:06:54 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: ldap.c,v 1.11.2.28 2007/12/19 19:29:32 millert Exp $";
 #endif /* lint */
 
 #ifndef LINE_MAX
@@ -76,20 +76,33 @@
 # define LDAP_OPT_SUCCESS LDAP_SUCCESS
 #endif
 
-#if defined(LDAP_X_OPT_CONNECT_TIMEOUT) && !defined(LDAP_OPT_X_CONNECT_TIMEOUT)
-#define LDAP_OPT_X_CONNECT_TIMEOUT	LDAP_OPT_X_CONNECT_TIMEOUT
-#endif
-
 #define	DPRINTF(args, level)	if (ldap_conf.debug >= level) warnx args
 
+#define CONF_BOOL	0
+#define CONF_INT	1
+#define CONF_STR	2
+
+#define SUDO_LDAP_SSL		1
+#define SUDO_LDAP_STARTTLS	2
+
+struct ldap_config_table {
+    const char *conf_str;	/* config file string */
+    short type;			/* CONF_BOOL, CONF_INT, CONF_STR */
+    short connected;		/* connection-specific value? */
+    int opt_val;		/* LDAP_OPT_* (or -1 for sudo internal) */
+    void *valp;			/* pointer into ldap_conf */
+};
+
 /* ldap configuration structure */
 struct ldap_config {
     int port;
     int version;
     int debug;
+    int ldap_debug;
     int tls_checkpeer;
     int timelimit;
     int bind_timelimit;
+    int ssl_mode;
     char *host;
     char *uri;
     char *binddn;
@@ -105,6 +118,67 @@
     char *tls_keyfile;
 } ldap_conf;
 
+struct ldap_config_table ldap_conf_table[] = {
+    { "sudoers_debug", CONF_INT, FALSE, -1, &ldap_conf.debug },
+    { "host", CONF_STR, FALSE, -1, &ldap_conf.host },
+    { "port", CONF_INT, FALSE, -1, &ldap_conf.port },
+    { "ssl", CONF_STR, FALSE, -1, &ldap_conf.ssl },
+    { "sslpath", CONF_STR, FALSE, -1, &ldap_conf.tls_certfile },
+    { "uri", CONF_STR, FALSE, -1, &ldap_conf.uri },
+#ifdef LDAP_OPT_DEBUG_LEVEL
+    { "debug", CONF_INT, FALSE, LDAP_OPT_DEBUG_LEVEL, &ldap_conf.ldap_debug },
+#endif
+#ifdef LDAP_OPT_PROTOCOL_VERSION
+    { "ldap_version", CONF_INT, TRUE, LDAP_OPT_PROTOCOL_VERSION,
+	&ldap_conf.version },
+#endif
+#ifdef LDAP_OPT_X_TLS_REQUIRE_CERT
+    { "tls_checkpeer", CONF_BOOL, FALSE, LDAP_OPT_X_TLS_REQUIRE_CERT,
+	&ldap_conf.tls_checkpeer },
+#endif
+#ifdef LDAP_OPT_X_TLS_CACERTFILE
+    { "tls_cacertfile", CONF_STR, FALSE, LDAP_OPT_X_TLS_CACERTFILE,
+	&ldap_conf.tls_cacertfile },
+#endif
+#ifdef LDAP_OPT_X_TLS_CACERTDIR
+    { "tls_cacertdir", CONF_STR, FALSE, LDAP_OPT_X_TLS_CACERTDIR,
+	&ldap_conf.tls_cacertdir },
+#endif
+#ifdef LDAP_OPT_X_TLS_RANDOM_FILE
+    { "tls_randfile", CONF_STR, FALSE, LDAP_OPT_X_TLS_RANDOM_FILE,
+	&ldap_conf.tls_random_file },
+#endif
+#ifdef LDAP_OPT_X_TLS_CIPHER_SUITE
+    { "tls_ciphers", CONF_STR, FALSE, LDAP_OPT_X_TLS_CIPHER_SUITE,
+	&ldap_conf.tls_cipher_suite },
+#endif
+#ifdef LDAP_OPT_X_TLS_CERTFILE
+    { "tls_cert", CONF_STR, FALSE, LDAP_OPT_X_TLS_CERTFILE,
+	&ldap_conf.tls_certfile },
+#else
+    { "tls_cert", CONF_STR, FALSE, -1, &ldap_conf.tls_certfile },
+#endif
+#ifdef LDAP_OPT_X_TLS_KEYFILE
+    { "tls_key", CONF_STR, FALSE, LDAP_OPT_X_TLS_KEYFILE,
+	&ldap_conf.tls_keyfile },
+#else
+    { "tls_key", CONF_STR, FALSE, -1, &ldap_conf.tls_keyfile },
+#endif
+#ifdef LDAP_OPT_NETWORK_TIMEOUT
+    { "bind_timelimit", CONF_INT, TRUE, -1 /* needs timeval, set manually */,
+	&ldap_conf.bind_timelimit },
+#elif defined(LDAP_X_OPT_CONNECT_TIMEOUT)
+    { "bind_timelimit", CONF_INT, TRUE, LDAP_X_OPT_CONNECT_TIMEOUT,
+	&ldap_conf.bind_timelimit },
+#endif
+    { "timelimit", CONF_INT, TRUE, LDAP_OPT_TIMELIMIT, &ldap_conf.timelimit },
+    { "binddn", CONF_STR, FALSE, -1, &ldap_conf.binddn },
+    { "bindpw", CONF_STR, FALSE, -1, &ldap_conf.bindpw },
+    { "rootbinddn", CONF_STR, FALSE, -1, &ldap_conf.rootbinddn },
+    { "sudoers_base", CONF_STR, FALSE, -1, &ldap_conf.base },
+    { NULL }
+};
+
 static void sudo_ldap_update_defaults __P((LDAP *));
 static void sudo_ldap_close __P((LDAP *));
 static LDAP *sudo_ldap_open __P((void));
@@ -495,16 +569,18 @@
 {
     FILE *f;
     char buf[LINE_MAX], *c, *keyword, *value;
+    struct ldap_config_table *cur;
 
     /* defaults */
     ldap_conf.version = 3;
-    ldap_conf.port = 389;
+    ldap_conf.port = -1;
     ldap_conf.tls_checkpeer = -1;
     ldap_conf.timelimit = -1;
     ldap_conf.bind_timelimit = -1;
 
     if ((f = fopen(_PATH_LDAP_CONF, "r")) == NULL)
 	return(FALSE);
+
     while (fgets(buf, sizeof(buf), f)) {
 	/* ignore text after comment character */
 	if ((c = strchr(buf, '#')) != NULL)
@@ -535,68 +611,29 @@
 	while (--c > value && isspace((unsigned char) *c))
 	    *c = '\0';
 
-	/* The following macros make the code much more readable */
-
-#define MATCH_S(x,y) if (!strcasecmp(keyword,x)) \
-    { efree(y); y=estrdup(value); }
-#define MATCH_I(x,y) if (!strcasecmp(keyword,x)) { y=atoi(value); }
-#define MATCH_B(x,y) if (!strcasecmp(keyword,x)) { y=_atobool(value); }
-
-	/*
-	 * Parse values using a continues chain of if else if else if else if
-	 * else ...
-	 */
-	MATCH_S("host", ldap_conf.host)
-	    else
-	MATCH_I("port", ldap_conf.port)
-	    else
-	MATCH_S("ssl", ldap_conf.ssl)
-	    else
-	MATCH_B("tls_checkpeer", ldap_conf.tls_checkpeer)
-	    else
-	MATCH_S("tls_cacertfile", ldap_conf.tls_cacertfile)
-	    else
-	MATCH_S("tls_cacertdir", ldap_conf.tls_cacertdir)
-	    else
-	MATCH_S("tls_randfile", ldap_conf.tls_random_file)
-	    else
-	MATCH_S("tls_ciphers", ldap_conf.tls_cipher_suite)
-	    else
-	MATCH_S("tls_cert", ldap_conf.tls_certfile)
-	    else
-	MATCH_S("tls_key", ldap_conf.tls_keyfile)
-	    else
-	MATCH_I("ldap_version", ldap_conf.version)
-	    else
-	MATCH_I("bind_timelimit", ldap_conf.bind_timelimit)
-	    else
-	MATCH_I("timelimit", ldap_conf.timelimit)
-	    else
-	MATCH_S("uri", ldap_conf.uri)
-	    else
-	MATCH_S("binddn", ldap_conf.binddn)
-	    else
-	MATCH_S("bindpw", ldap_conf.bindpw)
-	    else
-	MATCH_S("rootbinddn", ldap_conf.rootbinddn)
-	    else
-	MATCH_S("sudoers_base", ldap_conf.base)
-	    else
-	MATCH_I("sudoers_debug", ldap_conf.debug)
-	    else {
-
-	    /*
-	     * The keyword was unrecognized.  Since this config file is
-	     * shared by multiple programs, it is appropriate to silently
-	     * ignore options this program does not understand
-	     */
+	/* Look up keyword in config table. */
+	for (cur = ldap_conf_table; cur->conf_str != NULL; cur++) {
+	    if (strcasecmp(keyword, cur->conf_str) == 0) {
+		switch (cur->type) {
+		case CONF_BOOL:
+		    *(int *)(cur->valp) = _atobool(value);
+		    break;
+		case CONF_INT:
+		    *(int *)(cur->valp) = atoi(value);
+		    break;
+		case CONF_STR:
+		    efree(*(char **)(cur->valp));
+		    *(char **)(cur->valp) = estrdup(value);
+		    break;
+		}
+		break;
+	    }
 	}
-
     }
     fclose(f);
 
     if (!ldap_conf.host)
-	ldap_conf.host = estrdup("localhost");
+	ldap_conf.host = "localhost";
 
     if (ldap_conf.bind_timelimit > 0)
 	ldap_conf.bind_timelimit *= 1000;	/* convert to ms */
@@ -622,17 +659,47 @@
 	    ldap_conf.binddn : "(anonymous)");
 	fprintf(stderr, "bindpw       %s\n", ldap_conf.bindpw ?
 	    ldap_conf.bindpw : "(anonymous)");
-	fprintf(stderr, "bind_timelimit  %d\n", ldap_conf.bind_timelimit);
-	fprintf(stderr, "timelimit    %d\n", ldap_conf.timelimit);
-#ifdef HAVE_LDAP_START_TLS_S
+	if (ldap_conf.bind_timelimit > 0)
+	    fprintf(stderr, "bind_timelimit  %d\n", ldap_conf.bind_timelimit);
+	if (ldap_conf.timelimit > 0)
+	    fprintf(stderr, "timelimit    %d\n", ldap_conf.timelimit);
 	fprintf(stderr, "ssl          %s\n", ldap_conf.ssl ?
 	    ldap_conf.ssl : "(no)");
-#endif
+	if (ldap_conf.tls_checkpeer != -1)
+	    fprintf(stderr, "tls_checkpeer    %s\n", ldap_conf.tls_checkpeer ?
+		"(yes)" : "(no)");
+	if (ldap_conf.tls_cacertfile != NULL)
+	    fprintf(stderr, "tls_cacertfile   %s\n", ldap_conf.tls_cacertfile);
+	if (ldap_conf.tls_cacertdir != NULL)
+	    fprintf(stderr, "tls_cacertdir    %s\n", ldap_conf.tls_cacertdir);
+	if (ldap_conf.tls_random_file != NULL)
+	    fprintf(stderr, "tls_random_file  %s\n", ldap_conf.tls_random_file);
+	if (ldap_conf.tls_cipher_suite != NULL)
+	    fprintf(stderr, "tls_cipher_suite %s\n", ldap_conf.tls_cipher_suite);
+	if (ldap_conf.tls_certfile != NULL)
+	    fprintf(stderr, "tls_certfile     %s\n", ldap_conf.tls_certfile);
+	if (ldap_conf.tls_keyfile != NULL)
+	    fprintf(stderr, "tls_keyfile      %s\n", ldap_conf.tls_keyfile);
 	fprintf(stderr, "===================\n");
     }
     if (!ldap_conf.base)
 	return(FALSE);		/* if no base is defined, ignore LDAP */
 
+    /*
+     * Interpret SSL option
+     */
+    if (ldap_conf.ssl != NULL) {
+	    if (strcasecmp(ldap_conf.ssl, "start_tls") == 0)
+		ldap_conf.ssl_mode = SUDO_LDAP_STARTTLS;
+	    else if (_atobool(ldap_conf.ssl))
+		ldap_conf.ssl_mode = SUDO_LDAP_SSL;
+    }
+
+    /* Use port 389 for plaintext LDAP and port 636 for SSL LDAP */
+    if (ldap_conf.port < 0)
+	ldap_conf.port =
+	    ldap_conf.ssl_mode == SUDO_LDAP_SSL ? LDAPS_PORT : LDAP_PORT;
+
     /* If rootbinddn set, read in /etc/ldap.secret if it exists. */
     if (ldap_conf.rootbinddn) {
 	if ((f = fopen(_PATH_LDAP_SECRET, "r")) != NULL) {
@@ -746,148 +813,171 @@
 	printf("%s", sudo_ldap_cm_list);
 }
 
-/* macros to set option, error on failure plus consistent debugging */
-#define SET_OPTS(opt, val) do { \
-    if (ldap_conf.val != NULL) { \
-	if (ldap_conf.debug > 1) \
-	    fprintf(stderr, \
-		"ldap_set_option(LDAP_OPT_%s, \"%s\")\n", #opt, ldap_conf.val);\
-	rc = ldap_set_option(ld, LDAP_OPT_ ## opt, ldap_conf.val); \
-	if (rc != LDAP_OPT_SUCCESS) { \
-	    fprintf(stderr,"ldap_set_option(LDAP_OPT_%s, \"%s\")=%d: %s\n", \
-		#opt, ldap_conf.val, rc, ldap_err2string(rc)); \
-	    return(NULL); \
-	} \
-    } \
-} while(0)
-#define SET_OPTI(opt, val) do { \
-    if (ldap_conf.val >= 0) { \
-	if (ldap_conf.debug > 1) \
-	    fprintf(stderr, \
-		"ldap_set_option(LDAP_OPT_%s, %d)\n", #opt, ldap_conf.val); \
-	rc = ldap_set_option(ld, LDAP_OPT_ ## opt, &ldap_conf.val); \
-	if (rc != LDAP_OPT_SUCCESS) { \
-	    fprintf(stderr,"ldap_set_option(LDAP_OPT_%s, %d)=%d: %s\n", \
-		#opt, ldap_conf.val, rc, ldap_err2string(rc)); \
-	    return(NULL); \
-	} \
-    } \
-} while(0)
-
 /*
- * Open a connection to the LDAP server.
+ * Set LDAP options based on the config table.
  */
-static LDAP *
-sudo_ldap_open()
+int
+sudo_ldap_set_options(ld)
+    LDAP *ld;
 {
-    LDAP *ld = NULL;
+    struct ldap_config_table *cur;
     int rc;
 
-    if (!sudo_ldap_read_config())
-	return(NULL);
+    /* Set ber options */
+#ifdef LBER_OPT_DEBUG_LEVEL
+    if (ldap_conf.ldap_debug)
+	ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL, &ldap_conf.ldap_debug);
+#endif
 
-    /* attempt to setup ssl options */
-#ifdef LDAP_OPT_X_TLS_CACERTFILE
-    SET_OPTS(X_TLS_CACERTFILE, tls_cacertfile);
-#endif /* LDAP_OPT_X_TLS_CACERTFILE */
+    /* Set simple LDAP options */
+    for (cur = ldap_conf_table; cur->conf_str != NULL; cur++) {
+	LDAP *conn;
+	int ival;
+	char *sval;
 
-#ifdef LDAP_OPT_X_TLS_CACERTDIR
-    SET_OPTS(X_TLS_CACERTDIR, tls_cacertdir);
-#endif /* LDAP_OPT_X_TLS_CACERTDIR */
+	if (cur->opt_val == -1)
+	    continue;
 
-#ifdef LDAP_OPT_X_TLS_CERTFILE
-    SET_OPTS(X_TLS_CERTFILE, tls_certfile);
-#endif /* LDAP_OPT_X_TLS_CERTFILE */
+	conn = cur->connected ? ld : NULL;
+	switch (cur->type) {
+	case CONF_BOOL:
+	case CONF_INT:
+	    ival = *(int *)(cur->valp);
+	    if (ival >= 0) {
+		rc = ldap_set_option(conn, cur->opt_val, &ival);
+		if (rc != LDAP_OPT_SUCCESS) {
+		    warnx("ldap_set_option: %s -> %d: %s",
+			cur->conf_str, ival, ldap_err2string(rc));
+		    return(-1);
+		}
+		DPRINTF(("ldap_set_option: %s -> %d", cur->conf_str, ival), 1);
+	    }
+	    break;
+	case CONF_STR:
+	    sval = *(char **)(cur->valp);
+	    if (sval != NULL) {
+		rc = ldap_set_option(conn, cur->opt_val, sval);
+		if (rc != LDAP_OPT_SUCCESS) {
+		    warnx("ldap_set_option: %s -> %s: %s",
+			cur->conf_str, sval, ldap_err2string(rc));
+		    return(-1);
+		}
+		DPRINTF(("ldap_set_option: %s -> %s", cur->conf_str, sval), 1);
+	    }
+	    break;
+	}
+    }
 
-#ifdef LDAP_OPT_X_TLS_KEYFILE
-    SET_OPTS(X_TLS_KEYFILE, tls_keyfile);
-#endif /* LDAP_OPT_X_TLS_KEYFILE */
-
-#ifdef LDAP_OPT_X_TLS_CIPHER_SUITE
-    SET_OPTS(X_TLS_CIPHER_SUITE, tls_cipher_suite);
-#endif /* LDAP_OPT_X_TLS_CIPHER_SUITE */
-
-#ifdef LDAP_OPT_X_TLS_RANDOM_FILE
-    SET_OPTS(X_TLS_RANDOM_FILE, tls_random_file);
-#endif /* LDAP_OPT_X_TLS_RANDOM_FILE */
-
-#ifdef LDAP_OPT_X_TLS_REQUIRE_CERT
-    /* check the server certificate? */
-    SET_OPTI(X_TLS_REQUIRE_CERT, tls_checkpeer);
-#endif /* LDAP_OPT_X_TLS_REQUIRE_CERT */
-
-    /* set timelimit options */
-    SET_OPTI(TIMELIMIT, timelimit);
-
 #ifdef LDAP_OPT_NETWORK_TIMEOUT
+    /* Convert bind_timelimit to a timeval */
     if (ldap_conf.bind_timelimit > 0) {
 	struct timeval tv;
 	tv.tv_sec = ldap_conf.bind_timelimit / 1000;
 	tv.tv_usec = 0;
-	if (ldap_conf.debug > 1)
-	    fprintf(stderr, "ldap_set_option(LDAP_OPT_NETWORK_TIMEOUT, %ld)\n",
-	    tv.tv_sec);
 	rc = ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, &tv);
 	if (rc != LDAP_OPT_SUCCESS) {
-	    fprintf(stderr,"ldap_set_option(NETWORK_TIMEOUT, %ld)=%d: %s\n",
-	    tv.tv_sec, rc, ldap_err2string(rc));
-	    return(NULL);
+	    warnx("ldap_set_option(NETWORK_TIMEOUT, %ld): %s",
+		(long)tv.tv_sec, ldap_err2string(rc));
+	    return(-1);
 	}
+	DPRINTF(("ldap_set_option(LDAP_OPT_NETWORK_TIMEOUT, %ld)\n",
+	    (long)tv.tv_sec), 1);
     }
 #endif
 
-    /* attempt connect */
-#ifdef HAVE_LDAP_INITIALIZE
-    if (ldap_conf.uri) {
+#if defined(LDAP_OPT_X_TLS) && !defined(HAVE_LDAPSSL_INIT)
+    if (ldap_conf.ssl_mode == SUDO_LDAP_SSL) {
+	int val = LDAP_OPT_X_TLS_HARD;
+	rc = ldap_set_option(ld, LDAP_OPT_X_TLS, &val);
+	if (rc != LDAP_SUCCESS) {
+	    warnx("ldap_set_option(LDAP_OPT_X_TLS, LDAP_OPT_X_TLS_HARD): %s",
+		ldap_err2string(rc));
+	    return(-1);
+	}
 
-	DPRINTF(("ldap_initialize(ld,%s)", ldap_conf.uri), 2);
+    }
+#endif
+    return(0);
+}
 
+/*
+ * Open a connection to the LDAP server.
+ */
+static LDAP *
+sudo_ldap_open()
+{
+    LDAP *ld = NULL;
+    int rc;
+
+    if (!sudo_ldap_read_config())
+	return(NULL);
+
+#ifdef HAVE_LDAPSSL_INIT
+    if (ldap_conf.ssl_mode == SUDO_LDAP_SSL) {
+	DPRINTF(("ldapssl_clientauth_init(%s, %s)",
+	    ldap_conf.tls_certfile ? ldap_conf.tls_certfile : "NULL",
+	    ldap_conf.tls_keyfile ? ldap_conf.tls_keyfile : "NULL"), 2);
+	rc = ldapssl_clientauth_init(ldap_conf.tls_certfile, NULL,
+	    ldap_conf.tls_keyfile != NULL, ldap_conf.tls_keyfile, NULL);
+	if (rc != LDAP_SUCCESS) {
+	    warnx("unable to initialize SSL cert and key db: %s",
+		ldapssl_err2string(rc));
+	    return(NULL);
+	}
+    }
+#endif /* HAVE_LDAPSSL_INIT */
+
+    /* Connect to LDAP server */
+#ifdef HAVE_LDAP_INITIALIZE
+    if (ldap_conf.uri) {
+	DPRINTF(("ldap_initialize(ld, %s)", ldap_conf.uri), 2);
 	rc = ldap_initialize(&ld, ldap_conf.uri);
-	if (rc) {
-	    fprintf(stderr, "ldap_initialize()=%d : %s\n",
-		rc, ldap_err2string(rc));
+	if (rc != LDAP_SUCCESS) {
+	    warnx("unable to initialize LDAP: %s", ldap_err2string(rc));
 	    return(NULL);
 	}
     } else
 #endif /* HAVE_LDAP_INITIALIZE */
-    if (ldap_conf.host) {
-
-	DPRINTF(("ldap_init(%s,%d)", ldap_conf.host, ldap_conf.port), 2);
-
-	if ((ld = ldap_init(ldap_conf.host, ldap_conf.port)) == NULL) {
-	    fprintf(stderr, "ldap_init(): errno=%d : %s\n",
-		errno, strerror(errno));
+    {
+#ifdef HAVE_LDAPSSL_INIT
+	DPRINTF(("ldapssl_init(%s, %d, %d)", ldap_conf.host, ldap_conf.port,
+	    ldap_conf.ssl_mode == SUDO_LDAP_SSL), 2);
+	ld = ldapssl_init(ldap_conf.host, ldap_conf.port,
+	    ldap_conf.ssl_mode == SUDO_LDAP_SSL);
+#else
+	DPRINTF(("ldap_init(%s, %d)", ldap_conf.host, ldap_conf.port), 2);
+	ld = ldap_init(ldap_conf.host, ldap_conf.port);
+#endif /* HAVE_LDAPSSL_INIT */
+	if (ld == NULL) {
+	    warn("unable to initialize LDAP");
 	    return(NULL);
 	}
     }
-#ifdef LDAP_OPT_PROTOCOL_VERSION
 
-    /* Set the LDAP Protocol version */
-    SET_OPTI(PROTOCOL_VERSION, version);
+    /* Set LDAP options */
+    if (sudo_ldap_set_options(ld) < 0)
+	return(NULL);
 
-#endif /* LDAP_OPT_PROTOCOL_VERSION */
-
+    if (ldap_conf.ssl_mode == SUDO_LDAP_STARTTLS) {
 #ifdef HAVE_LDAP_START_TLS_S
-    /* Turn on TLS */
-    if (ldap_conf.ssl && !strcasecmp(ldap_conf.ssl, "start_tls")) {
 	rc = ldap_start_tls_s(ld, NULL, NULL);
 	if (rc != LDAP_SUCCESS) {
-	    fprintf(stderr, "ldap_start_tls_s(): %d: %s\n", rc,
-		ldap_err2string(rc));
+	    warnx("ldap_start_tls_s(): %s", ldap_err2string(rc));
 	    ldap_unbind(ld);
 	    return(NULL);
 	}
 	DPRINTF(("ldap_start_tls_s() ok"), 1);
-    }
+#else
+	warnx("start_tls specified but LDAP libs do not support ldap_start_tls_s()");
 #endif /* HAVE_LDAP_START_TLS_S */
+    }
 
     /* Actually connect */
     if ((rc = ldap_simple_bind_s(ld, ldap_conf.binddn, ldap_conf.bindpw))) {
-	fprintf(stderr, "ldap_simple_bind_s()=%d : %s\n",
-	    rc, ldap_err2string(rc));
+	warnx("ldap_simple_bind_s: %s", ldap_err2string(rc));
 	return(NULL);
     }
-    DPRINTF(("ldap_bind() ok"), 1);
+    DPRINTF(("ldap_simple_bind_s() ok"), 1);
 
     return(ld);
 }
@@ -901,7 +991,7 @@
 
     rc = ldap_search_s(ld, ldap_conf.base, LDAP_SCOPE_SUBTREE,
 	"cn=defaults", NULL, 0, &result);
-    if (!rc && (entry = ldap_first_entry(ld, result))) {
+    if (rc == LDAP_SUCCESS && (entry = ldap_first_entry(ld, result))) {
 	DPRINTF(("found:%s", ldap_get_dn(ld, entry)), 1);
 	sudo_ldap_parse_options(ld, entry);
     } else
@@ -952,7 +1042,7 @@
 	DPRINTF(("ldap search '%s'", filt), 1);
 	rc = ldap_search_s(ld, ldap_conf.base, LDAP_SCOPE_SUBTREE, filt,
 	    NULL, 0, &result);
-	if (rc)
+	if (rc != LDAP_SUCCESS)
 	    DPRINTF(("nothing found for '%s'", filt), 1);
 	efree(filt);
 
diff -ur sudo-1.6.9p9/sudo.c sudo-1.6.9p10/sudo.c
--- sudo-1.6.9p9/sudo.c	Mon Dec  3 11:12:03 2007
+++ sudo-1.6.9p10/sudo.c	Thu Dec 13 09:12:49 2007
@@ -102,7 +102,7 @@
 #include "version.h"
 
 #ifndef lint
-__unused __unused static const char rcsid[] = "$Sudo: sudo.c,v 1.369.2.33 2007/12/02 17:13:52 millert Exp $";
+__unused __unused static const char rcsid[] = "$Sudo: sudo.c,v 1.369.2.34 2007/12/13 14:12:49 millert Exp $";
 #endif /* lint */
 
 /*
Binary files sudo-1.6.9p9/sudo.cat and sudo-1.6.9p10/sudo.cat differ
diff -ur sudo-1.6.9p9/sudo.man.in sudo-1.6.9p10/sudo.man.in
--- sudo-1.6.9p9/sudo.man.in	Mon Dec  3 05:27:12 2007
+++ sudo-1.6.9p10/sudo.man.in	Mon Dec 17 17:11:10 2007
@@ -18,7 +18,7 @@
 .\" Agency (DARPA) and Air Force Research Laboratory, Air Force
 .\" Materiel Command, USAF, under agreement number F39502-99-1-0512.
 .\" 
-.\" $Sudo: sudo.man.in,v 1.29.2.16 2007/12/03 10:27:12 millert Exp $
+.\" $Sudo: sudo.man.in,v 1.29.2.17 2007/12/17 22:11:10 millert Exp $
 .\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
 .\"
 .\" Standard preamble:
@@ -150,7 +150,7 @@
 .\" ========================================================================
 .\"
 .IX Title "SUDO @mansectsu@"
-.TH SUDO @mansectsu@ "December  3, 2007" "1.6.9p8" "MAINTENANCE COMMANDS"
+.TH SUDO @mansectsu@ "December 17, 2007" "1.6.9p10" "MAINTENANCE COMMANDS"
 .SH "NAME"
 sudo, sudoedit \- execute a command as another user
 .SH "SYNOPSIS"
Binary files sudo-1.6.9p9/sudoers.cat and sudo-1.6.9p10/sudoers.cat differ
diff -ur sudo-1.6.9p9/sudoers.man.in sudo-1.6.9p10/sudoers.man.in
--- sudo-1.6.9p9/sudoers.man.in	Mon Dec  3 05:27:12 2007
+++ sudo-1.6.9p10/sudoers.man.in	Mon Dec 17 17:11:10 2007
@@ -18,7 +18,7 @@
 .\" Agency (DARPA) and Air Force Research Laboratory, Air Force
 .\" Materiel Command, USAF, under agreement number F39502-99-1-0512.
 .\" 
-.\" $Sudo: sudoers.man.in,v 1.45.2.18 2007/12/03 10:27:12 millert Exp $
+.\" $Sudo: sudoers.man.in,v 1.45.2.19 2007/12/17 22:11:10 millert Exp $
 .\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
 .\"
 .\" Standard preamble:
@@ -150,7 +150,7 @@
 .\" ========================================================================
 .\"
 .IX Title "SUDOERS @mansectform@"
-.TH SUDOERS @mansectform@ "December  3, 2007" "1.6.9p8" "MAINTENANCE COMMANDS"
+.TH SUDOERS @mansectform@ "December 17, 2007" "1.6.9p10" "MAINTENANCE COMMANDS"
 .SH "NAME"
 sudoers \- list of which users may execute what
 .SH "DESCRIPTION"
diff -ur sudo-1.6.9p9/version.h sudo-1.6.9p10/version.h
--- sudo-1.6.9p9/version.h	Mon Dec  3 05:34:32 2007
+++ sudo-1.6.9p10/version.h	Mon Dec 17 14:18:14 2007
@@ -17,12 +17,12 @@
  * Agency (DARPA) and Air Force Research Laboratory, Air Force
  * Materiel Command, USAF, under agreement number F39502-99-1-0512.
  *
- * $Sudo: version.h,v 1.66.2.12 2007/12/03 10:34:32 millert Exp $
+ * $Sudo: version.h,v 1.66.2.13 2007/12/17 19:18:14 millert Exp $
  */
 
 #ifndef _SUDO_VERSION_H
 #define _SUDO_VERSION_H
 
-static const char version[] = "1.6.9p9";
+static const char version[] = "1.6.9p10";
 
 #endif /* _SUDO_VERSION_H */
Binary files sudo-1.6.9p9/visudo.cat and sudo-1.6.9p10/visudo.cat differ
diff -ur sudo-1.6.9p9/visudo.man.in sudo-1.6.9p10/visudo.man.in
--- sudo-1.6.9p9/visudo.man.in	Fri Nov  2 15:15:16 2007
+++ sudo-1.6.9p10/visudo.man.in	Mon Dec 17 17:11:10 2007
@@ -17,7 +17,7 @@
 .\" Agency (DARPA) and Air Force Research Laboratory, Air Force
 .\" Materiel Command, USAF, under agreement number F39502-99-1-0512.
 .\" 
-.\" $Sudo: visudo.man.in,v 1.20.2.13 2007/11/02 19:15:16 millert Exp $
+.\" $Sudo: visudo.man.in,v 1.20.2.14 2007/12/17 22:11:10 millert Exp $
 .\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
 .\"
 .\" Standard preamble:
@@ -149,7 +149,7 @@
 .\" ========================================================================
 .\"
 .IX Title "VISUDO @mansectsu@"
-.TH VISUDO @mansectsu@ "November  2, 2007" "1.6.9p8" "MAINTENANCE COMMANDS"
+.TH VISUDO @mansectsu@ "December 17, 2007" "1.6.9p10" "MAINTENANCE COMMANDS"
 .SH "NAME"
 visudo \- edit the sudoers file
 .SH "SYNOPSIS"
