-Copyright (c) 2003-2009
+Copyright (c) 2003-2010
Todd C. Miller <Todd.Miller@courtesan.com>
Permission to use, copy, modify, and distribute this software for any
=item B<URI> ldap[s]://[hostname[:port]] ...
Specifies a whitespace-delimited list of one or more URIs describing
-the LDAP server(s) to connect to. The I<protocol> may be either B<ldap>
-or B<ldaps>, the latter being for servers that support TLS (SSL)
-encryption. If no I<port> is specified, the default is port 389 for
-C<ldap://> or port 636 for C<ldaps://>. If no I<hostname> is specified,
-B<sudo> will connect to B<localhost>. Only systems using the OpenSSL
-libraries support the mixing of C<ldap://> and C<ldaps://> URIs.
-The Netscape-derived libraries used on most commercial versions of
-Unix are only capable of supporting one or the other.
+the LDAP server(s) to connect to. The I<protocol> may be either
+B<ldap> or B<ldaps>, the latter being for servers that support TLS
+(SSL) encryption. If no I<port> is specified, the default is port
+389 for C<ldap://> or port 636 for C<ldaps://>. If no I<hostname>
+is specified, B<sudo> will connect to B<localhost>. Multiple B<URI>
+lines are treated identically to a B<URI> line containing multiple
+entries. Only systems using the OpenSSL libraries support the
+mixing of C<ldap://> and C<ldaps://> URIs. The Netscape-derived
+libraries used on most commercial versions of Unix are only capable
+of supporting one or the other.
=item B<HOST> name[:port] ...
int rootuse_sasl;
int ssl_mode;
char *host;
- char *uri;
+ struct ldap_config_list_str *uri;
char *binddn;
char *bindpw;
char *rootbinddn;
{ "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 },
+ { "uri", CONF_LIST_STR, FALSE, -1, &ldap_conf.uri },
#ifdef LDAP_OPT_DEBUG_LEVEL
{ "debug", CONF_INT, FALSE, LDAP_OPT_DEBUG_LEVEL, &ldap_conf.ldap_debug },
#endif
* where the trailing slash is optional.
*/
static int
-sudo_ldap_parse_uri(const char *uri_list)
+sudo_ldap_parse_uri(const struct ldap_config_list_str *uri_list)
{
char *buf, *uri, *host, *cp, *port;
char hostbuf[LINE_MAX];
int nldap = 0, nldaps = 0;
int rc = -1;
- buf = estrdup(uri_list);
- hostbuf[0] = '\0';
- for ((uri = strtok(buf, " \t")); uri != NULL; (uri = strtok(NULL, " \t"))) {
- if (strncasecmp(uri, "ldap://", 7) == 0) {
- nldap++;
- host = uri + 7;
- } else if (strncasecmp(uri, "ldaps://", 8) == 0) {
- nldaps++;
- host = uri + 8;
- } else {
- warningx("unsupported LDAP uri type: %s", uri);
- goto done;
- }
+ do {
+ buf = estrdup(uri_list->val);
+ hostbuf[0] = '\0';
+ for ((uri = strtok(buf, " \t")); uri != NULL; (uri = strtok(NULL, " \t"))) {
+ if (strncasecmp(uri, "ldap://", 7) == 0) {
+ nldap++;
+ host = uri + 7;
+ } else if (strncasecmp(uri, "ldaps://", 8) == 0) {
+ nldaps++;
+ host = uri + 8;
+ } else {
+ warningx("unsupported LDAP uri type: %s", uri);
+ goto done;
+ }
- /* trim optional trailing slash */
- if ((cp = strrchr(host, '/')) != NULL && cp[1] == '\0') {
- *cp = '\0';
- }
+ /* trim optional trailing slash */
+ if ((cp = strrchr(host, '/')) != NULL && cp[1] == '\0') {
+ *cp = '\0';
+ }
- if (hostbuf[0] != '\0') {
- if (strlcat(hostbuf, " ", sizeof(hostbuf)) >= sizeof(hostbuf))
- goto toobig;
- }
+ if (hostbuf[0] != '\0') {
+ if (strlcat(hostbuf, " ", sizeof(hostbuf)) >= sizeof(hostbuf))
+ goto toobig;
+ }
- if (*host == '\0')
- host = "localhost"; /* no host specified, use localhost */
+ if (*host == '\0')
+ host = "localhost"; /* no host specified, use localhost */
- if (strlcat(hostbuf, host, sizeof(hostbuf)) >= sizeof(hostbuf))
- goto toobig;
+ if (strlcat(hostbuf, host, sizeof(hostbuf)) >= sizeof(hostbuf))
+ goto toobig;
- /* If using SSL and no port specified, add port 636 */
- if (nldaps) {
- if ((port = strrchr(host, ':')) == NULL ||
- !isdigit((unsigned char)port[1]))
- if (strlcat(hostbuf, ":636", sizeof(hostbuf)) >= sizeof(hostbuf))
- goto toobig;
+ /* If using SSL and no port specified, add port 636 */
+ if (nldaps) {
+ if ((port = strrchr(host, ':')) == NULL ||
+ !isdigit((unsigned char)port[1]))
+ if (strlcat(hostbuf, ":636", sizeof(hostbuf)) >= sizeof(hostbuf))
+ goto toobig;
+ }
}
- }
- if (hostbuf[0] == '\0') {
- warningx("invalid uri: %s", uri_list);
- goto done;
- }
-
- if (nldaps != 0) {
- if (nldap != 0) {
- warningx("cannot mix ldap and ldaps URIs");
+ if (hostbuf[0] == '\0') {
+ warningx("invalid uri: %s", uri_list);
goto done;
}
- if (ldap_conf.ssl_mode == SUDO_LDAP_STARTTLS) {
- warningx("cannot mix ldaps and starttls");
- goto done;
+
+ if (nldaps != 0) {
+ if (nldap != 0) {
+ warningx("cannot mix ldap and ldaps URIs");
+ goto done;
+ }
+ if (ldap_conf.ssl_mode == SUDO_LDAP_STARTTLS) {
+ warningx("cannot mix ldaps and starttls");
+ goto done;
+ }
+ ldap_conf.ssl_mode = SUDO_LDAP_SSL;
}
- ldap_conf.ssl_mode = SUDO_LDAP_SSL;
- }
- free(ldap_conf.host);
- ldap_conf.host = estrdup(hostbuf);
+ free(ldap_conf.host);
+ ldap_conf.host = estrdup(hostbuf);
+ efree(buf);
+ } while ((uri_list = uri_list->next));
+
+ buf = NULL;
rc = 0;
done:
toobig:
errorx(1, "sudo_ldap_parse_uri: out of space building hostbuf");
}
+#else
+static char *
+sudo_ldap_join_uri(struct ldap_config_list_str *uri_list)
+{
+ struct ldap_config_list_str *uri;
+ size_t len = 0;
+ char *buf, *cp;
+
+ /* Usually just a single entry. */
+ if (uri_list->next == NULL)
+ return(estrdup(uri_list->val));
+
+ for (uri = uri_list; uri != NULL; uri = uri->next) {
+ len += strlen(uri->val) + 1;
+ }
+ buf = cp = emalloc(len);
+ buf[0] = '\0';
+ for (uri = uri_list; uri != NULL; uri = uri->next) {
+ cp += strlcpy(cp, uri->val, len - (cp - buf));
+ *cp++ = ' ';
+ }
+ cp[-1] = '\0';
+ return(buf);
+}
#endif /* HAVE_LDAP_INITIALIZE */
static int
sudo_printf(SUDO_CONV_ERROR_MSG, "LDAP Config Summary\n");
sudo_printf(SUDO_CONV_ERROR_MSG, "===================\n");
if (ldap_conf.uri) {
- sudo_printf(SUDO_CONV_ERROR_MSG, "uri %s\n",
- ldap_conf.uri);
+ struct ldap_config_list_str *uri = ldap_conf.uri;
+
+ do {
+ sudo_printf(SUDO_CONV_ERROR_MSG, "uri %s\n",
+ uri->val);
+ } while ((uri = uri->next) != NULL);
} else {
sudo_printf(SUDO_CONV_ERROR_MSG, "host %s\n",
ldap_conf.host ? ldap_conf.host : "(NONE)");
#ifndef HAVE_LDAP_INITIALIZE
/* Convert uri list to host list if no ldap_initialize(). */
if (ldap_conf.uri) {
- if (sudo_ldap_parse_uri(ldap_conf.uri) != 0)
+ struct ldap_config_list_str *uri = ldap_conf.uri;
+ if (sudo_ldap_parse_uri(uri) != 0)
return(FALSE);
- free(ldap_conf.uri);
- ldap_conf.uri = NULL;
+ do {
+ ldap_conf.uri = uri->next;
+ efree(uri);
+ } while ((uri = ldap_conf.uri));
ldap_conf.port = LDAP_PORT;
}
#endif
(long)tv.tv_sec, ldap_err2string(rc));
return(-1);
}
- DPRINTF(("ldap_set_option(LDAP_OPT_NETWORK_TIMEOUT, %ld)\n",
+ DPRINTF(("ldap_set_option(LDAP_OPT_NETWORK_TIMEOUT, %ld)",
(long)tv.tv_sec), 1);
}
#endif
ldap_err2string(rc));
return(-1);
}
- DPRINTF(("ldap_set_option(LDAP_OPT_X_TLS, LDAP_OPT_X_TLS_HARD)\n"), 1);
+ DPRINTF(("ldap_set_option(LDAP_OPT_X_TLS, LDAP_OPT_X_TLS_HARD)"), 1);
}
#endif
return(0);
/* Connect to LDAP server */
#ifdef HAVE_LDAP_INITIALIZE
if (ldap_conf.uri != NULL) {
- DPRINTF(("ldap_initialize(ld, %s)", ldap_conf.uri), 2);
- rc = ldap_initialize(&ld, ldap_conf.uri);
+ char *buf = sudo_ldap_join_uri(ldap_conf.uri);
+ DPRINTF(("ldap_initialize(ld, %s)", buf), 2);
+ rc = ldap_initialize(&ld, buf);
+ efree(buf);
} else
#endif
rc = sudo_ldap_init(&ld, ldap_conf.host, ldap_conf.port);