Add support for multiple URI lines by joining the contents and passing

the result to ldap_initialize.
This commit is contained in:
Todd C. Miller
2010-09-04 20:43:51 -04:00
parent 27f6558df9
commit df8ec6fc25
2 changed files with 111 additions and 71 deletions

View File

@@ -1,4 +1,4 @@
Copyright (c) 2003-2009 Copyright (c) 2003-2010
Todd C. Miller <Todd.Miller@courtesan.com> Todd C. Miller <Todd.Miller@courtesan.com>
Permission to use, copy, modify, and distribute this software for any Permission to use, copy, modify, and distribute this software for any
@@ -259,14 +259,16 @@ below in upper case but are parsed in a case-independent manner.
=item B<URI> ldap[s]://[hostname[:port]] ... =item B<URI> ldap[s]://[hostname[:port]] ...
Specifies a whitespace-delimited list of one or more URIs describing 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> the LDAP server(s) to connect to. The I<protocol> may be either
or B<ldaps>, the latter being for servers that support TLS (SSL) B<ldap> or B<ldaps>, the latter being for servers that support TLS
encryption. If no I<port> is specified, the default is port 389 for (SSL) encryption. If no I<port> is specified, the default is port
C<ldap://> or port 636 for C<ldaps://>. If no I<hostname> is specified, 389 for C<ldap://> or port 636 for C<ldaps://>. If no I<hostname>
B<sudo> will connect to B<localhost>. Only systems using the OpenSSL is specified, B<sudo> will connect to B<localhost>. Multiple B<URI>
libraries support the mixing of C<ldap://> and C<ldaps://> URIs. lines are treated identically to a B<URI> line containing multiple
The Netscape-derived libraries used on most commercial versions of entries. Only systems using the OpenSSL libraries support the
Unix are only capable of supporting one or the other. 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] ... =item B<HOST> name[:port] ...

View File

@@ -142,7 +142,7 @@ static struct ldap_config {
int rootuse_sasl; int rootuse_sasl;
int ssl_mode; int ssl_mode;
char *host; char *host;
char *uri; struct ldap_config_list_str *uri;
char *binddn; char *binddn;
char *bindpw; char *bindpw;
char *rootbinddn; char *rootbinddn;
@@ -166,7 +166,7 @@ static struct ldap_config_table ldap_conf_table[] = {
{ "port", CONF_INT, FALSE, -1, &ldap_conf.port }, { "port", CONF_INT, FALSE, -1, &ldap_conf.port },
{ "ssl", CONF_STR, FALSE, -1, &ldap_conf.ssl }, { "ssl", CONF_STR, FALSE, -1, &ldap_conf.ssl },
{ "sslpath", CONF_STR, FALSE, -1, &ldap_conf.tls_certfile }, { "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 #ifdef LDAP_OPT_DEBUG_LEVEL
{ "debug", CONF_INT, FALSE, LDAP_OPT_DEBUG_LEVEL, &ldap_conf.ldap_debug }, { "debug", CONF_INT, FALSE, LDAP_OPT_DEBUG_LEVEL, &ldap_conf.ldap_debug },
#endif #endif
@@ -313,70 +313,75 @@ toobig:
* where the trailing slash is optional. * where the trailing slash is optional.
*/ */
static int 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 *buf, *uri, *host, *cp, *port;
char hostbuf[LINE_MAX]; char hostbuf[LINE_MAX];
int nldap = 0, nldaps = 0; int nldap = 0, nldaps = 0;
int rc = -1; int rc = -1;
buf = estrdup(uri_list); do {
hostbuf[0] = '\0'; buf = estrdup(uri_list->val);
for ((uri = strtok(buf, " \t")); uri != NULL; (uri = strtok(NULL, " \t"))) { hostbuf[0] = '\0';
if (strncasecmp(uri, "ldap://", 7) == 0) { for ((uri = strtok(buf, " \t")); uri != NULL; (uri = strtok(NULL, " \t"))) {
nldap++; if (strncasecmp(uri, "ldap://", 7) == 0) {
host = uri + 7; nldap++;
} else if (strncasecmp(uri, "ldaps://", 8) == 0) { host = uri + 7;
nldaps++; } else if (strncasecmp(uri, "ldaps://", 8) == 0) {
host = uri + 8; nldaps++;
} else { host = uri + 8;
warningx("unsupported LDAP uri type: %s", uri); } else {
goto done; warningx("unsupported LDAP uri type: %s", uri);
} goto done;
}
/* trim optional trailing slash */ /* trim optional trailing slash */
if ((cp = strrchr(host, '/')) != NULL && cp[1] == '\0') { if ((cp = strrchr(host, '/')) != NULL && cp[1] == '\0') {
*cp = '\0'; *cp = '\0';
} }
if (hostbuf[0] != '\0') { if (hostbuf[0] != '\0') {
if (strlcat(hostbuf, " ", sizeof(hostbuf)) >= sizeof(hostbuf)) if (strlcat(hostbuf, " ", sizeof(hostbuf)) >= sizeof(hostbuf))
goto toobig;
}
if (*host == '\0')
host = "localhost"; /* no host specified, use localhost */
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; goto toobig;
} }
}
if (hostbuf[0] == '\0') {
warningx("invalid uri: %s", uri_list);
goto done;
}
if (nldaps != 0) { if (*host == '\0')
if (nldap != 0) { host = "localhost"; /* no host specified, use localhost */
warningx("cannot mix ldap and ldaps URIs");
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 (hostbuf[0] == '\0') {
warningx("invalid uri: %s", uri_list);
goto done; 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;
}
free(ldap_conf.host); if (nldaps != 0) {
ldap_conf.host = estrdup(hostbuf); 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;
}
free(ldap_conf.host);
ldap_conf.host = estrdup(hostbuf);
efree(buf);
} while ((uri_list = uri_list->next));
buf = NULL;
rc = 0; rc = 0;
done: done:
@@ -386,6 +391,30 @@ done:
toobig: toobig:
errorx(1, "sudo_ldap_parse_uri: out of space building hostbuf"); 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 */ #endif /* HAVE_LDAP_INITIALIZE */
static int static int
@@ -949,8 +978,12 @@ sudo_ldap_read_config(void)
sudo_printf(SUDO_CONV_ERROR_MSG, "LDAP Config Summary\n"); sudo_printf(SUDO_CONV_ERROR_MSG, "LDAP Config Summary\n");
sudo_printf(SUDO_CONV_ERROR_MSG, "===================\n"); sudo_printf(SUDO_CONV_ERROR_MSG, "===================\n");
if (ldap_conf.uri) { if (ldap_conf.uri) {
sudo_printf(SUDO_CONV_ERROR_MSG, "uri %s\n", struct ldap_config_list_str *uri = ldap_conf.uri;
ldap_conf.uri);
do {
sudo_printf(SUDO_CONV_ERROR_MSG, "uri %s\n",
uri->val);
} while ((uri = uri->next) != NULL);
} else { } else {
sudo_printf(SUDO_CONV_ERROR_MSG, "host %s\n", sudo_printf(SUDO_CONV_ERROR_MSG, "host %s\n",
ldap_conf.host ? ldap_conf.host : "(NONE)"); ldap_conf.host ? ldap_conf.host : "(NONE)");
@@ -1053,10 +1086,13 @@ sudo_ldap_read_config(void)
#ifndef HAVE_LDAP_INITIALIZE #ifndef HAVE_LDAP_INITIALIZE
/* Convert uri list to host list if no ldap_initialize(). */ /* Convert uri list to host list if no ldap_initialize(). */
if (ldap_conf.uri) { 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); return(FALSE);
free(ldap_conf.uri); do {
ldap_conf.uri = NULL; ldap_conf.uri = uri->next;
efree(uri);
} while ((uri = ldap_conf.uri));
ldap_conf.port = LDAP_PORT; ldap_conf.port = LDAP_PORT;
} }
#endif #endif
@@ -1551,7 +1587,7 @@ sudo_ldap_set_options(LDAP *ld)
(long)tv.tv_sec, ldap_err2string(rc)); (long)tv.tv_sec, ldap_err2string(rc));
return(-1); 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); (long)tv.tv_sec), 1);
} }
#endif #endif
@@ -1565,7 +1601,7 @@ sudo_ldap_set_options(LDAP *ld)
ldap_err2string(rc)); ldap_err2string(rc));
return(-1); 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 #endif
return(0); return(0);
@@ -1672,8 +1708,10 @@ sudo_ldap_open(struct sudo_nss *nss)
/* Connect to LDAP server */ /* Connect to LDAP server */
#ifdef HAVE_LDAP_INITIALIZE #ifdef HAVE_LDAP_INITIALIZE
if (ldap_conf.uri != NULL) { if (ldap_conf.uri != NULL) {
DPRINTF(("ldap_initialize(ld, %s)", ldap_conf.uri), 2); char *buf = sudo_ldap_join_uri(ldap_conf.uri);
rc = ldap_initialize(&ld, ldap_conf.uri); DPRINTF(("ldap_initialize(ld, %s)", buf), 2);
rc = ldap_initialize(&ld, buf);
efree(buf);
} else } else
#endif #endif
rc = sudo_ldap_init(&ld, ldap_conf.host, ldap_conf.port); rc = sudo_ldap_init(&ld, ldap_conf.host, ldap_conf.port);