int db_common_check_domain(void *ctxPtr, const char *addr) { DB_COMMON_CTX *ctx = (DB_COMMON_CTX *) ctxPtr; char *domain; if (ctx->domain) { if ((domain = strrchr(addr, '@')) != NULL) ++domain; if (domain == NULL || domain == addr + 1) return (0); if (match_list_match(ctx->domain, domain) == 0) return (0); } return (1); }
static const char *dict_ldap_lookup(DICT *dict, const char *name) { char *myname = "dict_ldap_lookup"; DICT_LDAP *dict_ldap = (DICT_LDAP *) dict; LDAPMessage *res = 0; static VSTRING *result; struct timeval tv; VSTRING *escaped_name = 0, *filter_buf = 0; int rc = 0; int sizelimit; char *sub, *end; dict_errno = 0; if (msg_verbose) msg_info("%s: In dict_ldap_lookup", myname); /* * If they specified a domain list for this map, then only search for * addresses in domains on the list. This can significantly reduce the * load on the LDAP server. */ if (dict_ldap->domain) { const char *p = strrchr(name, '@'); if (p == 0 || p == name || match_list_match(dict_ldap->domain, ++p) == 0) { if (msg_verbose) msg_info("%s: domain of %s not found in domain list", myname, name); return (0); } } /* * Initialize the result holder. */ if (result == 0) result = vstring_alloc(2); vstring_strcpy(result, ""); /* * Because the connection may be shared and invalidated via queries for * another map, update private copy of "ld" from shared connection * container. */ dict_ldap->ld = DICT_LDAP_CONN(dict_ldap)->conn_ld; /* * Connect to the LDAP server, if necessary. */ if (dict_ldap->ld == NULL) { if (msg_verbose) msg_info ("%s: No existing connection for LDAP source %s, reopening", myname, dict_ldap->ldapsource); dict_ldap_connect(dict_ldap); /* * if dict_ldap_connect() set dict_errno, abort. */ if (dict_errno) return (0); } else if (msg_verbose) msg_info("%s: Using existing connection for LDAP source %s", myname, dict_ldap->ldapsource); /* * Connection caching, means that the connection handle may have the * wrong size limit. Re-adjust before each query. This is cheap, just * sets a field in the ldap connection handle. We also do this in the * connect code, because we sometimes reconnect (below) in the middle of * a query. */ sizelimit = dict_ldap->size_limit ? dict_ldap->size_limit : LDAP_NO_LIMIT; if (ldap_set_option(dict_ldap->ld, LDAP_OPT_SIZELIMIT, &sizelimit) != LDAP_OPT_SUCCESS) msg_warn("%s: %s: Unable to set query result size limit to %ld.", myname, dict_ldap->ldapsource, dict_ldap->size_limit); /* * Prepare the query. */ tv.tv_sec = dict_ldap->timeout; tv.tv_usec = 0; escaped_name = vstring_alloc(20); filter_buf = vstring_alloc(30); /* * If any characters in the supplied address should be escaped per RFC * 2254, do so. Thanks to Keith Stevenson and Wietse. And thanks to * Samuel Tardieu for spotting that wildcard searches were being done in * the first place, which prompted the ill-conceived lookup_wildcards * parameter and then this more comprehensive mechanism. */ end = (char *) name + strlen((char *) name); sub = (char *) strpbrk((char *) name, "*()\\\0"); if (sub && sub != end) { if (msg_verbose) msg_info("%s: Found character(s) in %s that must be escaped", myname, name); for (sub = (char *) name; sub != end; sub++) { switch (*sub) { case '*': vstring_strcat(escaped_name, "\\2a"); break; case '(': vstring_strcat(escaped_name, "\\28"); break; case ')': vstring_strcat(escaped_name, "\\29"); break; case '\\': vstring_strcat(escaped_name, "\\5c"); break; case '\0': vstring_strcat(escaped_name, "\\00"); break; default: vstring_strncat(escaped_name, sub, 1); } } if (msg_verbose) msg_info("%s: After escaping, it's %s", myname, vstring_str(escaped_name)); } else vstring_strcpy(escaped_name, (char *) name); /* * Does the supplied query_filter even include a substitution? */ if ((char *) strchr(dict_ldap->query_filter, '%') == NULL) { /* * No, log the fact and continue. */ msg_warn("%s: %s: Fixed query_filter %s is probably useless", myname, dict_ldap->ldapsource, dict_ldap->query_filter); vstring_strcpy(filter_buf, dict_ldap->query_filter); } else { dict_ldap_expand_filter(dict_ldap->ldapsource, dict_ldap->query_filter, vstring_str(escaped_name), filter_buf); } /* * On to the search. */ if (msg_verbose) msg_info("%s: Searching with filter %s", myname, vstring_str(filter_buf)); rc = ldap_search_st(dict_ldap->ld, dict_ldap->search_base, dict_ldap->scope, vstring_str(filter_buf), dict_ldap->result_attributes->argv, 0, &tv, &res); if (rc == LDAP_SERVER_DOWN) { if (msg_verbose) msg_info("%s: Lost connection for LDAP source %s, reopening", myname, dict_ldap->ldapsource); ldap_unbind(dict_ldap->ld); dict_ldap->ld = DICT_LDAP_CONN(dict_ldap)->conn_ld = 0; dict_ldap_connect(dict_ldap); /* * if dict_ldap_connect() set dict_errno, abort. */ if (dict_errno) return (0); rc = ldap_search_st(dict_ldap->ld, dict_ldap->search_base, dict_ldap->scope, vstring_str(filter_buf), dict_ldap->result_attributes->argv, 0, &tv, &res); } if (rc == LDAP_SUCCESS) { /* * Search worked; extract the requested result_attribute. */ dict_ldap_get_values(dict_ldap, res, result); /* * OpenLDAP's ldap_next_attribute returns a bogus * LDAP_DECODING_ERROR; I'm ignoring that for now. */ rc = dict_ldap_get_errno(dict_ldap->ld); if (rc != LDAP_SUCCESS && rc != LDAP_DECODING_ERROR) msg_warn ("%s: Had some trouble with entries returned by search: %s", myname, ldap_err2string(rc)); if (msg_verbose) msg_info("%s: Search returned %s", myname, VSTRING_LEN(result) > 0 ? vstring_str(result) : "nothing"); } else { /* * Rats. The search didn't work. */ msg_warn("%s: Search error %d: %s ", myname, rc, ldap_err2string(rc)); /* * Tear down the connection so it gets set up from scratch on the * next lookup. */ ldap_unbind(dict_ldap->ld); dict_ldap->ld = DICT_LDAP_CONN(dict_ldap)->conn_ld = 0; /* * And tell the caller to try again later. */ dict_errno = DICT_ERR_RETRY; } /* * Cleanup. */ if (res != 0) ldap_msgfree(res); if (filter_buf != 0) vstring_free(filter_buf); if (escaped_name != 0) vstring_free(escaped_name); /* * If we had an error, return nothing, Otherwise, return the result, if * any. */ return (VSTRING_LEN(result) > 0 && !dict_errno ? vstring_str(result) : 0); }