*
* %W% (Berkeley) %G%
*
- * $Id: conf.c,v 1.7.2.10 2005/03/04 18:42:04 ezk Exp $
+ * $Id: conf.c,v 1.7.2.11 2005/03/15 04:14:57 ezk Exp $
*
*/
static int gopt_ldap_cache_maxmem(const char *val);
static int gopt_ldap_cache_seconds(const char *val);
static int gopt_ldap_hostports(const char *val);
+static int gopt_ldap_proto_version(const char *val);
static int gopt_local_domain(const char *val);
static int gopt_log_file(const char *val);
static int gopt_log_options(const char *val);
{"ldap_cache_maxmem", gopt_ldap_cache_maxmem},
{"ldap_cache_seconds", gopt_ldap_cache_seconds},
{"ldap_hostports", gopt_ldap_hostports},
+ {"ldap_proto_version", gopt_ldap_proto_version},
{"local_domain", gopt_local_domain},
{"log_file", gopt_log_file},
{"log_options", gopt_log_options},
}
+static int
+gopt_ldap_proto_version(const char *val)
+{
+#ifdef HAVE_MAP_LDAP
+ char *end;
+
+ gopt.ldap_proto_version = strtol((char *)val, &end, 10);
+ if (end == val) {
+ fprintf(stderr, "conf: bad ldap_proto_version option: %s\n",val);
+ return 1;
+ }
+
+ if (gopt.ldap_proto_version < 0 || gopt.ldap_proto_version > LDAP_VERSION_MAX) {
+ fprintf(stderr, "conf: bad ldap_proto_version option value: %s\n",val);
+ return 1;
+ }
+ switch (gopt.ldap_proto_version) {
+ /* XXX: what about LDAP_VERSION1? */
+ case LDAP_VERSION2:
+#ifdef LDAP_VERSION3
+ case LDAP_VERSION3:
+#endif /* LDAP_VERSION3 */
+#ifdef LDAP_VERSION4
+ case LDAP_VERSION4:
+#endif /* LDAP_VERSION4 */
+ break;
+ default:
+ fprintf(stderr, "conf: unsupported ldap_proto_version option value: %s\n",val);
+ return 1;
+ }
+ return 0;
+#else /* not HAVE_MAP_LDAP */
+ fprintf(stderr, "conf: ldap_proto_version option ignored. No LDAP support available.\n");
+ return 1;
+#endif /* not HAVE_MAP_LDAP */
+}
+
+
static int
gopt_log_file(const char *val)
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: info_ldap.c,v 1.9.2.11 2005/01/16 23:56:32 ezk Exp $
+ * $Id: info_ldap.c,v 1.9.2.12 2005/03/15 04:14:57 ezk Exp $
*
*/
* FORWARD DECLARATIONS:
*/
static int amu_ldap_rebind(ALD *a);
-static int get_ldap_timestamp(LDAP *ld, char *map, time_t *ts);
+static int get_ldap_timestamp(ALD *a, char *map, time_t *ts);
/*
}
+/*
+ * Special ldap_unbind function to handle SIGPIPE.
+ * We first ignore SIGPIPE, in case a remote LDAP server was
+ * restarted, then we reinstall the handler.
+ */
+static int
+amu_ldap_unbind(LDAP *ld)
+{
+ int e;
+#ifdef HAVE_SIGACTION
+ struct sigaction sa;
+#else /* not HAVE_SIGACTION */
+ void (*handler)(int);
+#endif /* not HAVE_SIGACTION */
+
+ dlog("amu_ldap_unbind()\n");
+
+#ifdef HAVE_SIGACTION
+ sa.sa_handler = SIG_IGN;
+ sa.sa_flags = 0;
+ sigemptyset(&(sa.sa_mask));
+ sigaddset(&(sa.sa_mask), SIGPIPE);
+ sigaction(SIGPIPE, &sa, &sa); /* set IGNORE, and get old action */
+#else /* not HAVE_SIGACTION */
+ handler = signal(SIGPIPE, SIG_IGN);
+#endif /* not HAVE_SIGACTION */
+
+ e = ldap_unbind(ld);
+
+#ifdef HAVE_SIGACTION
+ sigemptyset(&(sa.sa_mask));
+ sigaddset(&(sa.sa_mask), SIGPIPE);
+ sigaction(SIGPIPE, &sa, NULL);
+#else /* not HAVE_SIGACTION */
+ (void) signal(SIGPIPE, handler);
+#endif /* not HAVE_SIGACTION */
+
+ return e;
+}
+
+
static void
ald_free(ALD *a)
{
he_free(a->hostent);
cr_free(a->credentials);
if (a->ldap != NULL)
- ldap_unbind(a->ldap);
+ amu_ldap_unbind(a->ldap);
XFREE(a);
}
ALD *aldh;
CR *creds;
+ dlog("-> amu_ldap_init: map <%s>\n", map);
+
/*
* XXX: by checking that map_type must be defined, aren't we
* excluding the possibility of automatic searches through all
* map types?
*/
if (!gopt.map_type || !STREQ(gopt.map_type, AMD_LDAP_TYPE)) {
- return (ENOENT);
- }
-#ifdef DEBUG
- else {
+ plog(XLOG_WARNING, "amu_ldap_init called with map_type <%s>\n",
+ (gopt.map_type ? gopt.map_type : "null"));
+ } else {
dlog("Map %s is ldap\n", map);
}
-#endif /* DEBUG */
aldh = ALLOC(ALD);
creds = ALLOC(CR);
- aldh->ldap = NULL ;
+ aldh->ldap = NULL;
aldh->hostent = string2he(gopt.ldap_hostports);
if (aldh->hostent == NULL) {
plog(XLOG_USER, "Unable to parse hostport %s for ldap map %s",
creds->method = LDAP_AUTH_SIMPLE;
aldh->credentials = creds;
aldh->timestamp = 0;
-#ifdef DEBUG
+ aldh->ldap = NULL;
dlog("Trying for %s:%d\n", aldh->hostent->host, aldh->hostent->port);
-#endif /* DEBUG */
if (amu_ldap_rebind(aldh)) {
ald_free(aldh);
return (ENOENT);
}
m->map_data = (void *) aldh;
-#ifdef DEBUG
dlog("Bound to %s:%d\n", aldh->hostent->host, aldh->hostent->port);
-#endif /* DEBUG */
- if (get_ldap_timestamp(aldh->ldap, map, ts))
+ if (get_ldap_timestamp(aldh, map, ts))
return (ENOENT);
-#ifdef DEBUG
dlog("Got timestamp for map %s: %ld\n", map, *ts);
-#endif /* DEBUG */
return (0);
}
time_t now = clocktime();
int try;
+ dlog("-> amu_ldap_rebind\n");
+
if (a->ldap != NULL) {
if ((a->timestamp - now) > AMD_LDAP_TTL) {
-#ifdef DEBUG
- dlog("Reestablishing ldap connection\n");
-#endif /* DEBUG */
- ldap_unbind(a->ldap);
+ dlog("Re-establishing ldap connection\n");
+ amu_ldap_unbind(a->ldap);
a->timestamp = now;
+ a->ldap = NULL;
+ } else {
+ /* Assume all is OK. If it wasn't we'll be back! */
+ dlog("amu_ldap_rebind: timestamp OK\n");
+ return (0);
}
}
plog(XLOG_WARNING, "Unable to ldap_open to %s:%d\n", h->host, h->port);
break;
}
+#if LDAP_VERSION_MAX > LDAP_VERSION2
+ /* handle LDAPv3 and heigher, if available and amd.conf-igured */
+ if (gopt.ldap_proto_version > LDAP_VERSION2) {
+ if (!ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &gopt.ldap_proto_version)) {
+ dlog("amu_ldap_rebind: LDAP protocol version set to %ld\n",
+ gopt.ldap_proto_version);
+ } else {
+ plog(XLOG_WARNING, "Unable to set ldap protocol version to %ld\n",
+ gopt.ldap_proto_version);
+ break;
+ }
+ }
+#endif /* LDAP_VERSION_MAX > LDAP_VERSION2 */
if (ldap_bind_s(ld, c->who, c->pw, c->method) != LDAP_SUCCESS) {
plog(XLOG_WARNING, "Unable to ldap_bind to %s:%d as %s\n",
h->host, h->port, c->who);
#else /* not defined(HAVE_LDAP_ENABLE_CACHE) && defined(HAVE_EXTERN_LDAP_ENABLE_CACHE) */
plog(XLOG_WARNING, "ldap_enable_cache(%ld) is not available on this system!\n", gopt.ldap_cache_seconds);
#endif /* not defined(HAVE_LDAP_ENABLE_CACHE) && defined(HAVE_EXTERN_LDAP_ENABLE_CACHE) */
- a->ldap = ld;
- a->timestamp = now;
- return (0);
}
+ a->ldap = ld;
+ a->timestamp = now;
+ return (0);
}
plog(XLOG_WARNING, "Exhausted list of ldap servers, looping.\n");
}
static int
-get_ldap_timestamp(LDAP *ld, char *map, time_t *ts)
+get_ldap_timestamp(ALD *a, char *map, time_t *ts)
{
struct timeval tv;
char **vals, *end;
char filter[MAXPATHLEN];
int i, err = 0, nentries = 0;
- LDAPMessage *res, *entry;
+ LDAPMessage *res = NULL, *entry;
+
+ dlog("-> get_ldap_timestamp: map <%s>\n", map);
tv.tv_sec = 3;
tv.tv_usec = 0;
sprintf(filter, AMD_LDAP_TSFILTER, map);
-#ifdef DEBUG
dlog("Getting timestamp for map %s\n", map);
dlog("Filter is: %s\n", filter);
dlog("Base is: %s\n", gopt.ldap_base);
-#endif /* DEBUG */
for (i = 0; i < AMD_LDAP_RETRIES; i++) {
- err = ldap_search_st(ld,
+ err = ldap_search_st(a->ldap,
gopt.ldap_base,
LDAP_SCOPE_SUBTREE,
filter,
&res);
if (err == LDAP_SUCCESS)
break;
-#ifdef DEBUG
- dlog("Timestamp search timed out, trying again...\n");
-#endif /* DEBUG */
+ if (res) {
+ ldap_msgfree(res);
+ res = NULL;
+ }
+ plog(XLOG_USER, "Timestamp LDAP search attempt %d failed: %s\n",
+ i + 1, ldap_err2string(err));
+ if (err != LDAP_TIMEOUT) {
+ dlog("get_ldap_timestamp: unbinding...\n");
+ amu_ldap_unbind(a->ldap);
+ a->ldap = NULL;
+ if (amu_ldap_rebind(a))
+ return (ENOENT);
+ }
+ dlog("Timestamp search failed, trying again...\n");
}
if (err != LDAP_SUCCESS) {
*ts = 0;
plog(XLOG_USER, "LDAP timestamp search failed: %s\n",
ldap_err2string(err));
+ if (res)
+ ldap_msgfree(res);
return (ENOENT);
}
- nentries = ldap_count_entries(ld, res);
+ nentries = ldap_count_entries(a->ldap, res);
if (nentries == 0) {
plog(XLOG_USER, "No timestamp entry for map %s\n", map);
*ts = 0;
return (ENOENT);
}
- entry = ldap_first_entry(ld, res);
- vals = ldap_get_values(ld, entry, AMD_LDAP_TSATTR);
+ entry = ldap_first_entry(a->ldap, res);
+ vals = ldap_get_values(a->ldap, entry, AMD_LDAP_TSATTR);
if (ldap_count_values(vals) == 0) {
plog(XLOG_USER, "Missing timestamp value for map %s\n", map);
*ts = 0;
ldap_msgfree(res);
return (ENOENT);
}
-#ifdef DEBUG
dlog("TS value is:%s:\n", vals[0]);
-#endif /* DEBUG */
if (vals[0]) {
*ts = (time_t) strtol(vals[0], &end, 10);
ldap_value_free(vals);
ldap_msgfree(res);
-#ifdef DEBUG
dlog("The timestamp for %s is %ld (err=%d)\n", map, *ts, err);
-#endif /* DEBUG */
return (err);
}
int
amu_ldap_search(mnt_map *m, char *map, char *key, char **pval, time_t *ts)
{
- char **vals, filter[MAXPATHLEN];
+ char **vals, filter[MAXPATHLEN], filter2[2 * MAXPATHLEN];
+ char *f1, *f2;
struct timeval tv;
int i, err = 0, nvals = 0, nentries = 0;
- LDAPMessage *entry, *res;
+ LDAPMessage *entry, *res = NULL;
ALD *a = (ALD *) (m->map_data);
+ dlog("-> amu_ldap_search: map <%s>, key <%s>\n", map, key);
+
tv.tv_sec = 2;
tv.tv_usec = 0;
if (a == NULL) {
return (ENOENT);
sprintf(filter, AMD_LDAP_FILTER, map, key);
-#ifdef DEBUG
- dlog("Search with filter: %s\n", filter);
-#endif /* DEBUG */
+ /* "*" is special to ldap_search(); run through the filter escaping it. */
+ f1 = filter; f2 = filter2;
+ while (*f1) {
+ if (*f1 == '*') {
+ *f2++ = '\\'; *f2++ = '2'; *f2++ = 'a';
+ f1++;
+ } else {
+ *f2++ = *f1++;
+ }
+ }
+ *f2 = '\0';
+ dlog("Search with filter: <%s>\n", filter2);
for (i = 0; i < AMD_LDAP_RETRIES; i++) {
err = ldap_search_st(a->ldap,
gopt.ldap_base,
LDAP_SCOPE_SUBTREE,
- filter,
+ filter2,
0,
0,
&tv,
&res);
if (err == LDAP_SUCCESS)
break;
+ if (res) {
+ ldap_msgfree(res);
+ res = NULL;
+ }
+ plog(XLOG_USER, "LDAP search attempt %d failed: %s\n",
+ i + 1, ldap_err2string(err));
+ if (err != LDAP_TIMEOUT) {
+ dlog("amu_ldap_search: unbinding...\n");
+ amu_ldap_unbind(a->ldap);
+ a->ldap = NULL;
+ if (amu_ldap_rebind(a))
+ return (ENOENT);
+ }
}
switch (err) {
case LDAP_SUCCESS:
break;
case LDAP_NO_SUCH_OBJECT:
-#ifdef DEBUG
dlog("No object\n");
-#endif /* DEBUG */
- ldap_msgfree(res);
+ if (res)
+ ldap_msgfree(res);
return (ENOENT);
default:
plog(XLOG_USER, "LDAP search failed: %s\n",
ldap_err2string(err));
- ldap_msgfree(res);
+ if (res)
+ ldap_msgfree(res);
return (EIO);
}
nentries = ldap_count_entries(a->ldap, res);
-#ifdef DEBUG
dlog("Search found %d entries\n", nentries);
-#endif /* DEBUG */
if (nentries == 0) {
ldap_msgfree(res);
return (ENOENT);
ldap_msgfree(res);
return (EIO);
}
-#ifdef DEBUG
dlog("Map %s, %s => %s\n", map, key, vals[0]);
-#endif /* DEBUG */
if (vals[0]) {
*pval = strdup(vals[0]);
err = 0;
ALD *aldh = (ALD *) (m->map_data);
if (aldh == NULL) {
-#ifdef DEBUG
dlog("LDAP panic: unable to find map data\n");
-#endif /* DEBUG */
return (ENOENT);
}
if (amu_ldap_rebind(aldh)) {
return (ENOENT);
}
- if (get_ldap_timestamp(aldh->ldap, map, ts)) {
+ if (get_ldap_timestamp(aldh, map, ts)) {
return (ENOENT);
}
return (0);