The helper protocol for external ACLs [1] defines three possible return
values:
OK - Success. ACL test matches.
ERR - Success. ACL test fails to match.
BH - Failure. The helper encountered a problem.
The external acl helpers distributed with squid currently doesn't follow
this definition. For example, upon connection error, ERR is returned:
$ ext_ldap_group_acl ... -d
ext_ldap_group_acl: WARNING: could not bind to binddn 'Can't contact
LDAP server'
ERR
This is does not allow to distinguish "no match" and "error" either
and therefore negative caches "ERR", also in the case of an error.
Moreover there are multiple problems inside squid when trying to handle
BH responses:
- Squid-5 and squid-4 retries requests for BH responses but crashes
after the maximum retry number (currently 2) is reached.
- If an external acl helper return always BH (eg because the LDAP
server is down) squid sends infinitely new request to the helper.
This patch fixes the problems described above.
This is a Measurement Factory project
External ACL helpers error handling & caching
The helper protocol for external ACLs [1] defines three possible return values:
OK - Success. ACL test matches.
ERR - Success. ACL test fails to match.
BH - Failure. The helper encountered a problem.
The external acl helpers distributed with squid currently doesn't follow this
definition. For example, upon connection error, ERR is returned:
$ ext_ldap_group_acl ... -d
ext_ldap_group_acl: WARNING: could not bind to binddn 'Can't contact LDAP server'
ERR
This is does not allow to distinguish "no match" and "error" either and
therefore negative caches "ERR", also in the case of an error.
Moreover there are multiple problems inside squid when trying to handle BH
responses:
- Squid-5 and squid-4 retries requests for BH responses but crashes after the
maximum retry number (currently 2) is reached.
- If an external acl helper return always BH (eg because the LDAP server is
down) squid sends infinitely new request to the helper.
This is a Measurement Factory project
=== modified file 'src/acl/external/AD_group/ext_ad_group_acl.cc'
--- src/acl/external/AD_group/ext_ad_group_acl.cc 2017-01-01 00:12:22 +0000
+++ src/acl/external/AD_group/ext_ad_group_acl.cc 2017-01-09 10:02:17 +0000
@@ -802,58 +802,58 @@
DefaultDomain = xstrdup(machinedomain);
}
debug("%s " VERSION " " SQUID_BUILD_INFO " starting up...\n", argv[0]);
if (use_global)
debug("Domain Global group mode enabled using '%s' as default domain.\n", DefaultDomain);
if (use_case_insensitive_compare)
debug("Warning: running in case insensitive mode !!!\n");
atexit(CloseCOM);
/* Main Loop */
while (fgets(buf, HELPER_INPUT_BUFFER, stdin)) {
if (NULL == strchr(buf, '\n')) {
/* too large message received.. skip and deny */
fprintf(stderr, "%s: ERROR: Too large: %s\n", argv[0], buf);
while (fgets(buf, HELPER_INPUT_BUFFER, stdin)) {
fprintf(stderr, "%s: ERROR: Too large..: %s\n", argv[0], buf);
if (strchr(buf, '\n') != NULL)
break;
}
- SEND_ERR("Invalid Request. Too Long.");
+ SEND_BH(HLP_MSG("Invalid Request. Too Long."));
continue;
}
if ((p = strchr(buf, '\n')) != NULL)
*p = '\0'; /* strip \n */
if ((p = strchr(buf, '\r')) != NULL)
*p = '\0'; /* strip \r */
debug("Got '%s' from Squid (length: %d).\n", buf, strlen(buf));
if (buf[0] == '\0') {
- SEND_ERR("Invalid Request. No Input.");
+ SEND_BH(HLP_MSG("Invalid Request. No Input."));
continue;
}
username = strtok(buf, " ");
for (n = 0; (group = strtok(NULL, " ")) != NULL; ++n) {
rfc1738_unescape(group);
groups[n] = group;
}
groups[n] = NULL;
numberofgroups = n;
if (NULL == username) {
- SEND_ERR("Invalid Request. No Username.");
+ SEND_BH(HLP_MSG("Invalid Request. No Username."));
continue;
}
rfc1738_unescape(username);
if ((use_global ? Valid_Global_Groups(username, groups) : Valid_Local_Groups(username, groups))) {
SEND_OK("");
} else {
SEND_ERR("");
}
err = 0;
}
return 0;
}
=== modified file 'src/acl/external/LDAP_group/ext_ldap_group_acl.cc'
--- src/acl/external/LDAP_group/ext_ldap_group_acl.cc 2017-01-01 00:12:22 +0000
+++ src/acl/external/LDAP_group/ext_ldap_group_acl.cc 2017-01-09 10:44:19 +0000
@@ -454,166 +454,175 @@
HMODULE WLDAP32Handle;
WLDAP32Handle = GetModuleHandle("wldap32");
if ((Win32_ldap_start_tls_s = (PFldap_start_tls_s) GetProcAddress(WLDAP32Handle, LDAP_START_TLS_S)) == NULL) {
fprintf(stderr, PROGRAM_NAME ": FATAL: TLS (-Z) not supported on this platform.\n");
exit(1);
}
}
#endif
while (fgets(buf, HELPER_INPUT_BUFFER, stdin) != NULL) {
int found = 0;
if (!strchr(buf, '\n')) {
/* too large message received.. skip and deny */
fprintf(stderr, "%s: ERROR: Input Too large: %s\n", argv[0], buf);
while (fgets(buf, sizeof(buf), stdin)) {
fprintf(stderr, "%s: ERROR: Input Too large..: %s\n", argv[0], buf);
if (strchr(buf, '\n') != NULL)
break;
}
- SEND_ERR("");
+ SEND_BH(HLP_MSG("Input too large"));
continue;
}
user = strtok(buf, " \n");
if (!user) {
debug("%s: Invalid request: No Username given\n", argv[0]);
- SEND_ERR("Invalid request. No Username");
+ SEND_BH(HLP_MSG("Invalid request. No Username"));
continue;
}
rfc1738_unescape(user);
if (strip_nt_domain) {
char *u = strrchr(user, '\\');
if (!u)
u = strrchr(user, '/');
if (!u)
u = strrchr(user, '+');
if (u && u[1])
user = u + 1;
}
if (strip_kerberos_realm) {
char *u = strchr(user, '@');
if (u != NULL) {
*u = '\0';
}
}
if (use_extension_dn) {
extension_dn = strtok(NULL, " \n");
if (!extension_dn) {
debug("%s: Invalid request: Extension DN configured, but none sent.\n", argv[0]);
- SEND_ERR("Invalid Request. Extension DN required.");
+ SEND_BH(HLP_MSG("Invalid Request. Extension DN required"));
continue;
}
rfc1738_unescape(extension_dn);
}
+ const char *broken = nullptr;
while (!found && user && (group = strtok(NULL, " \n")) != NULL) {
rfc1738_unescape(group);
recover:
if (ld == NULL) {
#if HAS_URI_SUPPORT
if (strstr(ldapServer, "://") != NULL) {
rc = ldap_initialize(&ld, ldapServer);
if (rc != LDAP_SUCCESS) {
+ broken = HLP_MSG("Unable to connect to LDAP server");
fprintf(stderr, "%s: ERROR: Unable to connect to LDAPURI:%s\n", argv[0], ldapServer);
break;
}
} else
#endif
#if NETSCAPE_SSL
if (sslpath) {
if (!sslinit && (ldapssl_client_init(sslpath, NULL) != LDAP_SUCCESS)) {
fprintf(stderr, "FATAL: Unable to initialise SSL with cert path %s\n", sslpath);
exit(1);
} else {
++sslinit;
}
if ((ld = ldapssl_init(ldapServer, port, 1)) == NULL) {
fprintf(stderr, "FATAL: Unable to connect to SSL LDAP server: %s port:%d\n",
ldapServer, port);
exit(1);
}
} else
#endif
if ((ld = ldap_init(ldapServer, port)) == NULL) {
- fprintf(stderr, "ERROR: Unable to connect to LDAP server:%s port:%d\n", ldapServer, port);
+ broken = HLP_MSG("Unable to connect to LDAP server");
+ fprintf(stderr, "ERROR: %s:%s port:%d\n", broken, ldapServer, port);
break;
}
if (connect_timeout)
squid_ldap_set_connect_timeout(ld, connect_timeout);
#ifdef LDAP_VERSION3
if (version == -1) {
version = LDAP_VERSION3;
}
if (ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version) != LDAP_SUCCESS) {
- fprintf(stderr, "ERROR: Could not set LDAP_OPT_PROTOCOL_VERSION %d\n",
- version);
+ broken = HLP_MSG("Could not set LDAP_OPT_PROTOCOL_VERSION");
+ fprintf(stderr, "ERROR: %s %d\n", broken, version);
ldap_unbind(ld);
ld = NULL;
break;
}
if (use_tls) {
#ifdef LDAP_OPT_X_TLS
if (version != LDAP_VERSION3) {
fprintf(stderr, "FATAL: TLS requires LDAP version 3\n");
exit(1);
} else if (ldap_start_tls_s(ld, NULL, NULL) != LDAP_SUCCESS) {
- fprintf(stderr, "ERROR: Could not Activate TLS connection\n");
+ broken = HLP_MSG("Could not Activate TLS connection");
+ fprintf(stderr, "ERROR: %s\n", broken);
ldap_unbind(ld);
ld = NULL;
break;
}
#else
fprintf(stderr, "FATAL: TLS not supported with your LDAP library\n");
exit(1);
#endif
}
#endif
squid_ldap_set_timelimit(ld, timelimit);
squid_ldap_set_referrals(ld, !noreferrals);
squid_ldap_set_aliasderef(ld, aliasderef);
if (binddn && bindpasswd && *binddn && *bindpasswd) {
rc = ldap_simple_bind_s(ld, binddn, bindpasswd);
if (rc != LDAP_SUCCESS) {
- fprintf(stderr, PROGRAM_NAME ": WARNING: could not bind to binddn '%s'\n", ldap_err2string(rc));
+ broken = HLP_MSG("could not bind");
+ fprintf(stderr, PROGRAM_NAME ": WARNING: %s to binddn '%s'\n", broken, ldap_err2string(rc));
ldap_unbind(ld);
ld = NULL;
break;
}
}
debug("Connected OK\n");
}
- if (searchLDAP(ld, group, user, extension_dn) == 0) {
+ int searchResult = searchLDAP(ld, group, user, extension_dn);
+ if (searchResult == 0) {
found = 1;
break;
- } else {
+ } else if (searchResult < 0){
if (tryagain) {
tryagain = 0;
ldap_unbind(ld);
ld = NULL;
goto recover;
}
+ broken = HLP_MSG("LDAP search error");
}
}
if (found)
SEND_OK("");
+ else if (broken)
+ SEND_BH(broken);
else {
SEND_ERR("");
}
if (ld != NULL) {
if (!persistent || (squid_ldap_errno(ld) != LDAP_SUCCESS && squid_ldap_errno(ld) != LDAP_INVALID_CREDENTIALS)) {
ldap_unbind(ld);
ld = NULL;
} else {
tryagain = 1;
}
}
}
if (ld)
ldap_unbind(ld);
return 0;
}
static std::string
ldap_escape_value(const std::string &src)
@@ -705,83 +714,83 @@
ldapssl_err2string(sslerr) << ")" << std::endl;
}
#endif
return false;
}
typedef const std::unique_ptr<LDAPMessage, decltype(&ldap_msgfree)> LdapResult;
static int
searchLDAPGroup(LDAP * ld, const char *group, const char *member, const char *extension_dn)
{
std::string filter;
LDAPMessage *res = NULL;
int rc;
char *searchattr[] = {(char *) LDAP_NO_ATTRS, NULL};
const std::string searchbase = build_searchbase(extension_dn, basedn);
if (!build_filter(filter, searchfilter, member, group)) {
std::cerr << PROGRAM_NAME << ": ERROR: Failed to construct LDAP search filter. filter=\"" <<
filter.c_str() << "\", user=\"" << member << "\", group=\"" << group << "\"" << std::endl;
- return 1;
+ return -1;
}
debug("group filter '%s', searchbase '%s'\n", filter.c_str(), searchbase.c_str());
rc = ldap_search_s(ld, searchbase.c_str(), searchscope, filter.c_str(), searchattr, 1, &res);
LdapResult ldapRes(res, ldap_msgfree);
if (!ldap_search_ok(rc))
- return 1;
+ return -1;
return ldap_first_entry(ld, ldapRes.get()) ? 0 : 1;
}
static void
formatWithString(std::string &formatted, const std::string &value)
{
size_t start_pos = 0;
while ((start_pos = formatted.find("%s", start_pos)) != std::string::npos) {
formatted.replace(start_pos, 2, value);
start_pos += 2;
}
}
static int
searchLDAP(LDAP * ld, char *group, char *login, char *extension_dn)
{
const char *current_userdn = userbasedn ? userbasedn : basedn;
if (usersearchfilter) {
LDAPMessage *res = NULL;
LDAPMessage *entry;
int rc;
char *userdn;
char *searchattr[] = {(char *) LDAP_NO_ATTRS, NULL};
const std::string searchbase = build_searchbase(extension_dn, current_userdn);
std::string filter(usersearchfilter);
const std::string escaped_login = ldap_escape_value(login);
formatWithString(filter, escaped_login);
debug("user filter '%s', searchbase '%s'\n", filter.c_str(), searchbase.c_str());
rc = ldap_search_s(ld, searchbase.c_str(), searchscope, filter.c_str(), searchattr, 1, &res);
LdapResult ldapRes(res, ldap_msgfree);
if (!ldap_search_ok(rc))
- return 1;
+ return -1;
entry = ldap_first_entry(ld, ldapRes.get());
if (!entry) {
std::cerr << PROGRAM_NAME << ": WARNING: User '" << login <<
" not found in '" << searchbase.c_str() << "'" << std::endl;
return 1;
}
userdn = ldap_get_dn(ld, entry);
rc = searchLDAPGroup(ld, group, userdn, extension_dn);
squid_ldap_memfree(userdn);
return rc;
} else if (userdnattr) {
std::stringstream str;
str << userdnattr << "=" << login << ", ";
if (extension_dn && *extension_dn)
str << extension_dn << ", ";
str << current_userdn;
return searchLDAPGroup(ld, group, str.str().c_str(), extension_dn);
} else {
return searchLDAPGroup(ld, group, login, extension_dn);
}
=== modified file 'src/acl/external/LM_group/ext_lm_group_acl.cc'
--- src/acl/external/LM_group/ext_lm_group_acl.cc 2017-01-01 00:12:22 +0000
+++ src/acl/external/LM_group/ext_lm_group_acl.cc 2017-01-09 09:59:00 +0000
@@ -544,56 +544,56 @@
if (use_global) {
debug("Domain Global group mode enabled using '%s' as default domain.\n", DefaultDomain);
}
if (use_case_insensitive_compare) {
debug("Warning: running in case insensitive mode !!!\n");
}
if (use_PDC_only) {
debug("Warning: using only PDCs for group validation !!!\n");
}
/* Main Loop */
while (fgets(buf, HELPER_INPUT_BUFFER, stdin)) {
if (NULL == strchr(buf, '\n')) {
/* too large message received.. skip and deny */
debug("%s: ERROR: Too large: %s\n", argv[0], buf);
while (fgets(buf, HELPER_INPUT_BUFFER, stdin)) {
debug("%s: ERROR: Too large..: %s\n", argv[0], buf);
if (strchr(buf, '\n') != NULL)
break;
}
- SEND_ERR("Input Too Long.");
+ SEND_BH(HLP_MSG("Input Too Long."));
continue;
}
if ((p = strchr(buf, '\n')) != NULL)
*p = '\0'; /* strip \n */
if ((p = strchr(buf, '\r')) != NULL)
*p = '\0'; /* strip \r */
debug("Got '%s' from Squid (length: %d).\n", buf, strlen(buf));
if (buf[0] == '\0') {
- SEND_ERR("Invalid Request.");
+ SEND_BH(HLP_MSG("Invalid Request."));
continue;
}
username = strtok(buf, " ");
for (n = 0; (group = strtok(NULL, " ")) != NULL; ++n) {
rfc1738_unescape(group);
groups[n] = group;
}
groups[n] = NULL;
if (NULL == username) {
- SEND_ERR("Invalid Request. No Username.");
+ SEND_BH(HLP_MSG("Invalid Request. No Username."));
continue;
}
rfc1738_unescape(username);
if ((use_global ? Valid_Global_Groups(username, groups) : Valid_Local_Groups(username, groups))) {
SEND_OK("");
} else {
SEND_ERR("");
}
}
return 0;
}
=== modified file 'src/acl/external/SQL_session/ext_sql_session_acl.pl.in'
--- src/acl/external/SQL_session/ext_sql_session_acl.pl.in 2017-01-01 00:12:22 +0000
+++ src/acl/external/SQL_session/ext_sql_session_acl.pl.in 2017-01-05 11:01:47 +0000
@@ -178,31 +178,31 @@
close_db();
open_db() || return undef;
$sth->execute($uid) || return undef;;
}
return $sth;
}
my $status;
$|=1;
while (<>) {
my $string = $_;
$string =~ m/^(\d+)\s(.*)$/;
my ($cid, $uid) = ($1, $2);
$status = "ERR";
$cid =~ s/%(..)/pack("H*", $1)/ge;
$uid =~ s/%(..)/pack("H*", $1)/ge;
print(stderr "Received: Channel=".$cid.", UID='".$uid."'\n") if ($debug);
- $status = $cid . " ERR message=\"database error\"";
+ $status = $cid . " BH message=\"database error\"";
my $sth = query_db($uid) || next;
print(stderr "Rows: ". $sth->rows()."\n") if ($debug);
$status = $cid . " ERR message=\"unknown UID '".$uid."'\"";
my $row = $sth->fetchrow_hashref() || next;
$status = $cid . " OK" . ($row->{'user'} ne "" ? " user=" . $row->{'user'} : "" ) . ($row->{'tag'} ne "" ? " tag=" . $row->{'tag'} : "" );
$sth->finish();
} continue {
close_db() if (!$persist);
print $status . "\n";
}
=== modified file 'src/acl/external/eDirectory_userip/ext_edirectory_userip_acl.cc'
--- src/acl/external/eDirectory_userip/ext_edirectory_userip_acl.cc 2017-01-01 00:12:22 +0000
+++ src/acl/external/eDirectory_userip/ext_edirectory_userip_acl.cc 2017-01-05 11:05:44 +0000
@@ -1741,41 +1741,41 @@
edui_elap = 0;
k = strlen(bufa);
/* BINARY DEBUGGING *
local_printfx("while() -> bufa[%" PRIuSIZE "]: %s", k, bufa);
for (i = 0; i < k; ++i)
local_printfx("%02X", bufa[i]);
local_printfx("\n");
* BINARY DEBUGGING */
/* Check for CRLF */
p = strchr(bufa, '\n');
if (p != NULL)
*p = '\0';
p = strchr(bufa, '\r');
if (p != NULL)
*p = '\0';
p = strchr(bufa, ' ');
/* No space given, but group string is required --> ERR */
if ((edui_conf.mode & EDUI_MODE_GROUP) && (p == NULL)) {
debug("while() -> Search group is missing. (required)\n");
- local_printfx("ERR message=\"(Search Group Required)\"\n");
+ local_printfx("BH message=\"(Search Group Required)\"\n");
continue;
}
x = 0;
/* Open LDAP connection */
if (!(edui_ldap.status & LDAP_INIT_S)) {
InitLDAP(&edui_ldap);
debug("InitLDAP() -> %s\n", ErrLDAP(LDAP_ERR_SUCCESS));
if (edui_conf.mode & EDUI_MODE_PERSIST) /* Setup persistant mode */
edui_ldap.status |= LDAP_PERSIST_S;
}
if ((edui_ldap.status & LDAP_IDLE_S) && (edui_elap > 0)) {
edui_ldap.idle_time = edui_ldap.idle_time + edui_elap;
}
if ((edui_ldap.status & LDAP_PERSIST_S) && (edui_ldap.status & LDAP_IDLE_S) && (edui_ldap.idle_time > edui_conf.persist_timeout)) {
debug("while() -> Connection timed out after %d seconds\n", (int)(edui_ldap.idle_time));
x = CloseLDAP(&edui_ldap);
debug("CloseLDAP(-) -> %s\n", ErrLDAP(x));
}
edui_ldap.err = -1;
@@ -1784,161 +1784,167 @@
if (x != LDAP_ERR_SUCCESS) {
/* Failed to connect */
debug("OpenLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err));
} else {
debug("OpenLDAP(-, %s, %d) -> %s\n", edui_conf.host, edui_conf.port, ErrLDAP(x));
x = SetVerLDAP(&edui_ldap, edui_conf.ver);
if (x != LDAP_ERR_SUCCESS) {
/* Failed to set version */
debug("SetVerLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err));
} else
debug("SetVerLDAP(-, %d) -> %s\n", edui_conf.ver, ErrLDAP(x));
}
}
edui_ldap.err = -1;
if (!(edui_ldap.status & LDAP_BIND_S) && (edui_conf.mode & EDUI_MODE_TLS)) {
/* TLS binding */
x = BindLDAP(&edui_ldap, edui_conf.dn, edui_conf.passwd, LDAP_AUTH_TLS);
if (x != LDAP_ERR_SUCCESS) {
/* Unable to bind */
debug("BindLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err));
- local_printfx("ERR message=\"(BindLDAP: %s - %s)\"\n", ErrLDAP(x), ldap_err2string(edui_ldap.err));
+ local_printfx("BH message=\"(BindLDAP: %s - %s)\"\n", ErrLDAP(x), ldap_err2string(edui_ldap.err));
continue;
} else
debug("BindLDAP(-, %s, %s, (LDAP_AUTH_TLS)) -> %s\n", edui_conf.dn, edui_conf.passwd, ErrLDAP(x));
} else if (!(edui_ldap.status & LDAP_BIND_S)) {
if (edui_conf.dn[0] != '\0') {
/* Simple binding - using dn / passwd for authorization */
x = BindLDAP(&edui_ldap, edui_conf.dn, edui_conf.passwd, LDAP_AUTH_SIMPLE);
if (x != LDAP_ERR_SUCCESS) {
/* Unable to bind */
debug("BindLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err));
- local_printfx("ERR message=\"(BindLDAP: %s - %s)\"\n", ErrLDAP(x), ldap_err2string(edui_ldap.err));
+ local_printfx("BH message=\"(BindLDAP: %s - %s)\"\n", ErrLDAP(x), ldap_err2string(edui_ldap.err));
continue;
} else
debug("BindLDAP(-, %s, %s, (LDAP_AUTH_SIMPLE)) -> %s\n", edui_conf.dn, edui_conf.passwd, ErrLDAP(x));
} else {
/* Anonymous binding */
x = BindLDAP(&edui_ldap, edui_conf.dn, edui_conf.passwd, LDAP_AUTH_NONE);
if (x != LDAP_ERR_SUCCESS) {
/* Unable to bind */
debug("BindLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err));
- local_printfx("ERR message=\"(BindLDAP: %s - %s)\"\n", ErrLDAP(x), ldap_err2string(edui_ldap.err));
+ local_printfx("BH message=\"(BindLDAP: %s - %s)\"\n", ErrLDAP(x), ldap_err2string(edui_ldap.err));
continue;
} else
debug("BindLDAP(-, -, -, (LDAP_AUTH_NONE)) -> %s\n", ErrLDAP(x));
}
}
edui_ldap.err = -1;
if (edui_ldap.status & LDAP_PERSIST_S) {
x = ResetLDAP(&edui_ldap);
if (x != LDAP_ERR_SUCCESS) {
/* Unable to reset */
debug("ResetLDAP() -> %s\n", ErrLDAP(x));
} else
debug("ResetLDAP() -> %s\n", ErrLDAP(x));
}
if (x != LDAP_ERR_SUCCESS) {
/* Everything failed --> ERR */
debug("while() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err));
CloseLDAP(&edui_ldap);
- local_printfx("ERR message=\"(General Failure: %s)\"\n", ErrLDAP(x));
+ local_printfx("BH message=\"(General Failure: %s)\"\n", ErrLDAP(x));
continue;
}
edui_ldap.err = -1;
/* If we got a group string, split it */
if (p != NULL) {
/* Split string */
debug("StringSplit(%s, ' ', %s, %" PRIuSIZE ")\n", bufa, bufb, sizeof(bufb));
i = StringSplit(bufa, ' ', bufb, sizeof(bufb));
if (i > 0) {
debug("StringSplit(%s, %s) done. Result: %" PRIuSIZE "\n", bufa, bufb, i);
/* Got a group to match against */
x = ConvertIP(&edui_ldap, bufb);
if (x < 0) {
debug("ConvertIP() -> %s\n", ErrLDAP(x));
- local_printfx("ERR message=\"(ConvertIP: %s)\"\n", ErrLDAP(x));
+ local_printfx("BH message=\"(ConvertIP: %s)\"\n", ErrLDAP(x));
} else {
edui_ldap.err = -1;
debug("ConvertIP(-, %s) -> Result[%d]: %s\n", bufb, x, edui_ldap.search_ip);
x = SearchFilterLDAP(&edui_ldap, bufa);
if (x < 0) {
debug("SearchFilterLDAP() -> %s\n", ErrLDAP(x));
- local_printfx("ERR message=\"(SearchFilterLDAP: %s)\"\n", ErrLDAP(x));
+ local_printfx("BH message=\"(SearchFilterLDAP: %s)\"\n", ErrLDAP(x));
} else {
/* Do Search */
edui_ldap.err = -1;
debug("SearchFilterLDAP(-, %s) -> Length: %u\n", bufa, x);
x = SearchLDAP(&edui_ldap, edui_ldap.scope, edui_ldap.search_filter, (char **) &search_attrib);
if (x != LDAP_ERR_SUCCESS) {
debug("SearchLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err));
- local_printfx("ERR message=\"(SearchLDAP: %s)\"\n", ErrLDAP(x));
+ local_printfx("BH message=\"(SearchLDAP: %s)\"\n", ErrLDAP(x));
} else {
edui_ldap.err = -1;
debug("SearchLDAP(-, %d, %s, -) -> %s\n", edui_conf.scope, edui_ldap.search_filter, ErrLDAP(x));
x = SearchIPLDAP(&edui_ldap);
- if (x != LDAP_ERR_SUCCESS) {
- debug("SearchIPLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err));
+ if (x == LDAP_ERR_NOTFOUND) {
+ debug("SearchIPLDAP() -> %s\n", ErrLDAP(x));
local_printfx("ERR message=\"(SearchIPLDAP: %s)\"\n", ErrLDAP(x));
- } else {
+ } else if (x == LDAP_ERR_SUCCESS) {
debug("SearchIPLDAP(-, %s) -> %s\n", edui_ldap.userid, ErrLDAP(x));
local_printfx("OK user=%s\n", edui_ldap.userid); /* Got userid --> OK user=<userid> */
+ } else {
+ debug("SearchIPLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err));
+ local_printfx("BH message=\"(SearchIPLDAP: %s)\"\n", ErrLDAP(x));
}
}
/* Clear for next query */
memset(bufc, '\0', sizeof(bufc));
}
}
} else {
debug("StringSplit() -> Error: %" PRIuSIZE "\n", i);
- local_printfx("ERR message=\"(StringSplit Error %" PRIuSIZE ")\"\n", i);
+ local_printfx("BH message=\"(StringSplit Error %" PRIuSIZE ")\"\n", i);
}
} else {
/* No group to match against, only an IP */
x = ConvertIP(&edui_ldap, bufa);
if (x < 0) {
debug("ConvertIP() -> %s\n", ErrLDAP(x));
- local_printfx("ERR message=\"(ConvertIP: %s)\"\n", ErrLDAP(x));
+ local_printfx("BH message=\"(ConvertIP: %s)\"\n", ErrLDAP(x));
} else {
debug("ConvertIP(-, %s) -> Result[%d]: %s\n", bufa, x, edui_ldap.search_ip);
/* Do search */
x = SearchFilterLDAP(&edui_ldap, NULL);
if (x < 0) {
debug("SearchFilterLDAP() -> %s\n", ErrLDAP(x));
- local_printfx("ERR message=\"(SearchFilterLDAP: %s)\"\n", ErrLDAP(x));
+ local_printfx("BH message=\"(SearchFilterLDAP: %s)\"\n", ErrLDAP(x));
} else {
edui_ldap.err = -1;
debug("SearchFilterLDAP(-, NULL) -> Length: %u\n", x);
x = SearchLDAP(&edui_ldap, edui_ldap.scope, edui_ldap.search_filter, (char **) &search_attrib);
if (x != LDAP_ERR_SUCCESS) {
debug("SearchLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(x));
- local_printfx("ERR message=\"(SearchLDAP: %s)\"\n", ErrLDAP(x));
+ local_printfx("BH message=\"(SearchLDAP: %s)\"\n", ErrLDAP(x));
} else {
edui_ldap.err = -1;
debug("SearchLDAP(-, %d, %s, -) -> %s\n", edui_conf.scope, edui_ldap.search_filter, ErrLDAP(x));
x = SearchIPLDAP(&edui_ldap);
- if (x != LDAP_ERR_SUCCESS) {
- debug("SearchIPLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err));
+ if (x == LDAP_ERR_NOTFOUND) {
+ debug("SearchIPLDAP() -> %s\n", ErrLDAP(x));
local_printfx("ERR message=\"(SearchIPLDAP: %s)\"\n", ErrLDAP(x));
- } else {
+ } else if (x == LDAP_ERR_SUCCESS) {
debug("SearchIPLDAP(-, %s) -> %s\n", edui_ldap.userid, ErrLDAP(x));
local_printfx("OK user=%s\n", edui_ldap.userid); /* Got a userid --> OK user=<userid> */
+ } else if (x != LDAP_ERR_SUCCESS) {
+ debug("SearchIPLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x), ldap_err2string(edui_ldap.err));
+ local_printfx("BH message=\"(SearchIPLDAP: %s)\"\n", ErrLDAP(x));
}
}
}
/* Clear for next query */
memset(bufc, '\0', sizeof(bufc));
}
}
/* Clear buffer and close for next data, if not persistent */
edui_ldap.err = -1;
memset(bufa, '\0', sizeof(bufa));
if (!(edui_ldap.status & LDAP_PERSIST_S)) {
x = CloseLDAP(&edui_ldap);
debug("CloseLDAP(-) -> %s\n", ErrLDAP(x));
}
}
debug("Terminating.\n");
return 1;
}
=== modified file 'src/acl/external/file_userip/ext_file_userip_acl.cc'
--- src/acl/external/file_userip/ext_file_userip_acl.cc 2017-01-01 00:12:22 +0000
+++ src/acl/external/file_userip/ext_file_userip_acl.cc 2017-01-09 10:02:58 +0000
@@ -249,46 +249,46 @@
usage(program_name);
exit(1);
}
FILE *FH = fopen(filename, "r");
if (!FH) {
int xerrno = errno;
fprintf(stderr, "%s: FATAL: Unable to open file '%s': %s", program_name, filename, xstrerr(xerrno));
exit(1);
}
current_entry = load_dict(FH);
while (fgets(line, HELPER_INPUT_BUFFER, stdin)) {
if ((cp = strchr (line, '\n')) == NULL) {
/* too large message received.. skip and deny */
fprintf(stderr, "%s: ERROR: Input Too Large: %s\n", program_name, line);
while (fgets(line, sizeof(line), stdin)) {
fprintf(stderr, "%s: ERROR: Input Too Large..: %s\n", program_name, line);
if (strchr(line, '\n') != NULL)
break;
}
- SEND_ERR("Input Too Large.");
+ SEND_BH(HLP_MSG("Input Too Large."));
continue;
}
*cp = '\0';
address = strtok(line, " \t");
username = strtok(NULL, " \t");
if (!address || !username) {
debug("%s: unable to read tokens\n", program_name);
- SEND_ERR("Invalid Input.");
+ SEND_BH(HLP_MSG("Invalid Input."));
continue;
}
rfc1738_unescape(address);
rfc1738_unescape(username);
int result = dict_lookup(current_entry, username, address);
debug("%s: result: %d\n", program_name, result);
if (result != 0) {
SEND_OK("");
} else {
SEND_ERR("");
}
}
fclose (FH);
return 0;
}
=== modified file 'src/acl/external/time_quota/ext_time_quota_acl.cc'
--- src/acl/external/time_quota/ext_time_quota_acl.cc 2017-01-01 00:12:22 +0000
+++ src/acl/external/time_quota/ext_time_quota_acl.cc 2017-01-09 09:58:12 +0000
@@ -435,30 +435,30 @@
}
}
log_info("Starting %s\n", __FILE__);
setbuf(stdout, NULL);
init_db();
if ( optind + 1 != argc ) {
usage();
exit(1);
} else {
readConfig(argv[optind]);
}
log_info("Waiting for requests...\n");
while (fgets(request, HELPER_INPUT_BUFFER, stdin)) {
// we expect the following line syntax: %LOGIN
const char *user_key = strtok(request, " \n");
if (!user_key) {
- SEND_BH("message=\"User name missing\"");
+ SEND_BH(HLP_MSG("User name missing"));
continue;
}
processActivity(user_key);
}
log_info("Ending %s\n", __FILE__);
shutdown_db();
return 0;
}
=== modified file 'src/acl/external/unix_group/check_group.cc'
--- src/acl/external/unix_group/check_group.cc 2017-01-01 00:12:22 +0000
+++ src/acl/external/unix_group/check_group.cc 2017-01-09 10:01:32 +0000
@@ -186,46 +186,46 @@
default:
usage(argv[0]);
exit(1);
}
}
if (optind < argc) {
fprintf(stderr, "FATAL: Unknown option '%s'\n", argv[optind]);
usage(argv[0]);
exit(1);
}
while (fgets(buf, HELPER_INPUT_BUFFER, stdin)) {
j = 0;
if ((p = strchr(buf, '\n')) == NULL) {
/* too large message received.. skip and deny */
fprintf(stderr, "ERROR: %s: Too large: %s\n", argv[0], buf);
while (fgets(buf, sizeof(buf), stdin)) {
fprintf(stderr, "ERROR: %s: Too large..: %s\n", argv[0], buf);
if (strchr(buf, '\n') != NULL)
break;
}
- SEND_ERR("Username Input too large.");
+ SEND_BH(HLP_MSG("Username Input too large."));
continue;
}
*p = '\0';
if ((p = strtok(buf, " ")) == NULL) {
- SEND_ERR("No username given.");
+ SEND_BH(HLP_MSG("No username given."));
continue;
} else {
user = p;
rfc1738_unescape(user);
if (strip_dm) {
suser = strchr(user, '\\');
if (!suser) suser = strchr(user, '/');
if (suser && suser[1]) user = suser + 1;
}
if (strip_rm) {
suser = strchr(user, '@');
if (suser) *suser = '\0';
}
/* check groups supplied by Squid */
while ((p = strtok(NULL, " ")) != NULL) {
rfc1738_unescape(p);
if (check_pw == 1)
j += validate_user_pw(user, p);
j += validate_user_gr(user, p);
}
=== modified file 'src/external_acl.cc'
--- src/external_acl.cc 2017-01-01 00:12:22 +0000
+++ src/external_acl.cc 2017-01-09 08:27:56 +0000
@@ -699,41 +699,43 @@
SBufList rv;
rv.push_back(SBuf(acl->def->name));
for (wordlist *arg = acl->arguments; arg; arg = arg->next) {
SBuf s;
s.Printf(" %s", arg->key);
rv.push_back(s);
}
return rv;
}
/******************************************************************
* external_acl cache
*/
static void
external_acl_cache_touch(external_acl * def, const ExternalACLEntryPointer &entry)
{
// this must not be done when nothing is being cached.
- if (def->cache_size <= 0 || (def->ttl <= 0 && entry->result == 1) || (def->negative_ttl <= 0 && entry->result != 1))
+ if (def->cache_size <= 0 ||
+ entry->result == ACCESS_DUNNO ||
+ (def->ttl <= 0 && entry->result == ACCESS_ALLOWED) || (def->negative_ttl <= 0 && entry->result != ACCESS_ALLOWED))
return;
dlinkDelete(&entry->lru, &def->lru_list);
ExternalACLEntry *e = const_cast<ExternalACLEntry *>(entry.getRaw()); // XXX: make hash a std::map of Pointer.
dlinkAdd(e, &entry->lru, &def->lru_list);
}
static char *
makeExternalAclKey(ACLFilledChecklist * ch, external_acl_data * acl_data)
{
static MemBuf mb;
mb.reset();
// check for special case tokens in the format
for (Format::Token *t = acl_data->def->format.format; t ; t = t->next) {
if (t->type == Format::LFT_EXT_ACL_NAME) {
// setup for %ACL
safe_free(ch->al->lastAclName);
ch->al->lastAclName = xstrdup(acl_data->name);
@@ -765,73 +767,81 @@
if (t->type == Format::LFT_USER_IDENT) {
if (!*ch->rfc931) {
// if we fail to go async, we still return NULL and the caller
// will detect the failure in ACLExternal::match().
(void)ch->goAsync(IdentLookup::Instance());
return NULL;
}
}
#endif
}
// assemble the full helper lookup string
acl_data->def->format.assemble(mb, ch->al, 0);
return mb.buf;
}
static int
external_acl_entry_expired(external_acl * def, const ExternalACLEntryPointer &entry)
{
- if (def->cache_size <= 0)
+ if (def->cache_size <= 0 || entry->result == ACCESS_DUNNO)
return 1;
- if (entry->date + (entry->result == 1 ? def->ttl : def->negative_ttl) < squid_curtime)
+ if (entry->date + (entry->result == ACCESS_ALLOWED ? def->ttl : def->negative_ttl) < squid_curtime)
return 1;
else
return 0;
}
static int
external_acl_grace_expired(external_acl * def, const ExternalACLEntryPointer &entry)
{
- if (def->cache_size <= 0)
+ if (def->cache_size <= 0 || entry->result == ACCESS_DUNNO)
return 1;
int ttl;
- ttl = entry->result == 1 ? def->ttl : def->negative_ttl;
+ ttl = entry->result == ACCESS_ALLOWED ? def->ttl : def->negative_ttl;
ttl = (ttl * (100 - def->grace)) / 100;
if (entry->date + ttl <= squid_curtime)
return 1;
else
return 0;
}
static ExternalACLEntryPointer
external_acl_cache_add(external_acl * def, const char *key, ExternalACLEntryData const & data)
{
ExternalACLEntryPointer entry;
+ // do not cache ACCESS_DUNNO results
// do not bother caching this result if TTL is going to expire it immediately
- if (def->cache_size <= 0 || (def->ttl <= 0 && data.result == 1) || (def->negative_ttl <= 0 && data.result != 1)) {
+ if (def->cache_size <= 0 ||
+ data.result == ACCESS_DUNNO ||
+ (def->ttl <= 0 && data.result == ACCESS_ALLOWED) || (def->negative_ttl <= 0 && data.result != ACCESS_ALLOWED)) {
debugs(82,6, HERE);
+
+ if (data.result == ACCESS_DUNNO) {
+ if (const ExternalACLEntryPointer oldentry = static_cast<ExternalACLEntry *>(hash_lookup(def->cache, key)))
+ external_acl_cache_delete(def, oldentry);
+ }
entry = new ExternalACLEntry;
entry->key = xstrdup(key);
entry->update(data);
entry->def = def;
return entry;
}
entry = static_cast<ExternalACLEntry *>(hash_lookup(def->cache, key));
debugs(82, 2, "external_acl_cache_add: Adding '" << key << "' = " << data.result);
if (entry != NULL) {
debugs(82, 3, "updating existing entry");
entry->update(data);
external_acl_cache_touch(def, entry);
return entry;
}
entry = new ExternalACLEntry;
entry->key = xstrdup(key);
entry->update(data);
@@ -899,88 +909,81 @@
* Keywords:
*
* user= The users name (login)
* message= Message describing the reason
* tag= A string tag to be applied to the request that triggered the acl match.
* applies to both OK and ERR responses.
* Won't override existing request tags.
* log= A string to be used in access logging
*
* Other keywords may be added to the protocol later
*
* value needs to be URL-encoded or enclosed in double quotes (")
* with \-escaping on any whitespace, quotes, or slashes (\).
*/
static void
externalAclHandleReply(void *data, const Helper::Reply &reply)
{
externalAclState *state = static_cast<externalAclState *>(data);
externalAclState *next;
ExternalACLEntryData entryData;
- entryData.result = ACCESS_DENIED;
debugs(82, 2, HERE << "reply=" << reply);
if (reply.result == Helper::Okay)
entryData.result = ACCESS_ALLOWED;
- // XXX: handle other non-DENIED results better
+ else if (reply.result == Helper::Error)
+ entryData.result = ACCESS_DENIED;
+ else //BrokenHelper,TimedOut or Unknown. Should not cached.
+ entryData.result = ACCESS_DUNNO;
// XXX: make entryData store a proper Helper::Reply object instead of copying.
entryData.notes.append(&reply.notes);
const char *label = reply.notes.findFirst("tag");
if (label != NULL && *label != '\0')
entryData.tag = label;
label = reply.notes.findFirst("message");
if (label != NULL && *label != '\0')
entryData.message = label;
label = reply.notes.findFirst("log");
if (label != NULL && *label != '\0')
entryData.log = label;
#if USE_AUTH
label = reply.notes.findFirst("user");
if (label != NULL && *label != '\0')
entryData.user = label;
label = reply.notes.findFirst("password");
if (label != NULL && *label != '\0')
entryData.password = label;
#endif
dlinkDelete(&state->list, &state->def->queue);
ExternalACLEntryPointer entry;
- if (cbdataReferenceValid(state->def)) {
- // only cache OK and ERR results.
- if (reply.result == Helper::Okay || reply.result == Helper::Error)
- entry = external_acl_cache_add(state->def, state->key, entryData);
- else {
- const ExternalACLEntryPointer oldentry = static_cast<ExternalACLEntry *>(hash_lookup(state->def->cache, state->key));
-
- if (oldentry != NULL)
- external_acl_cache_delete(state->def, oldentry);
- }
- }
+ if (cbdataReferenceValid(state->def))
+ entry = external_acl_cache_add(state->def, state->key, entryData);
do {
void *cbdata;
if (state->callback && cbdataReferenceValidDone(state->callback_data, &cbdata))
state->callback(cbdata, entry);
next = state->queue;
state->queue = NULL;
delete state;
state = next;
} while (state);
}
void
ACLExternal::ExternalAclLookup(ACLChecklist *checklist, ACLExternal * me)
{
ExternalACLLookup::Start(checklist, me->data, false);
}
=== modified file 'src/helper.cc'
--- src/helper.cc 2017-01-01 00:12:22 +0000
+++ src/helper.cc 2017-01-05 17:14:57 +0000
@@ -879,52 +879,53 @@
return r;
}
/// Calls back with a pointer to the buffer with the helper output
static void
helperReturnBuffer(helper_server * srv, helper * hlp, char * msg, size_t msgSize, char * msgEnd)
{
if (Helper::Xaction *r = srv->replyXaction) {
const bool hasSpace = r->reply.accumulate(msg, msgSize);
if (!hasSpace) {
debugs(84, DBG_IMPORTANT, "ERROR: Disconnecting from a " <<
"helper that overflowed " << srv->rbuf_sz << "-byte " <<
"Squid input buffer: " << hlp->id_name << " #" << srv->index);
srv->closePipesSafely(hlp->id_name);
return;
}
if (!msgEnd)
return; // We are waiting for more data.
- HLPCB *callback = r->request.callback;
- r->request.callback = nullptr;
-
bool retry = false;
- void *cbdata = nullptr;
- if (cbdataReferenceValidDone(r->request.data, &cbdata)) {
+ if (cbdataReferenceValid(r->request.data)) {
r->reply.finalize();
if (r->reply.result == Helper::BrokenHelper && r->request.retries < MAX_RETRIES) {
debugs(84, DBG_IMPORTANT, "ERROR: helper: " << r->reply << ", attempt #" << (r->request.retries + 1) << " of 2");
retry = true;
- } else
+ } else {
+ HLPCB *callback = r->request.callback;
+ r->request.callback = nullptr;
+ void *cbdata = nullptr;
+ cbdataReferenceValidDone(r->request.data, &cbdata);
callback(cbdata, r->reply);
+ }
}
-- srv->stats.pending;
++ srv->stats.replies;
++ hlp->stats.replies;
srv->answer_time = current_time;
srv->dispatch_time = r->request.dispatch_time;
hlp->stats.avg_svc_time =
Math::intAverage(hlp->stats.avg_svc_time,
tvSubMsec(r->request.dispatch_time, current_time),
hlp->stats.replies, REDIRECT_AV_FACTOR);
// release or re-submit parsedRequestXaction object
srv->replyXaction = nullptr;
if (retry) {
++r->request.retries;
=== modified file 'src/helper/protocol_defines.h'
--- src/helper/protocol_defines.h 2017-01-01 00:12:22 +0000
+++ src/helper/protocol_defines.h 2017-01-09 09:53:45 +0000
@@ -36,28 +36,31 @@
*/
#ifndef __SQUID_HELPERS_DEFINES_H
#define __SQUID_HELPERS_DEFINES_H
/*
* This file contains several macro definitions which are
* useful and shared between helpers.
*/
#include <iostream>
#define HELPER_INPUT_BUFFER 8196
/* send OK result to Squid with a string parameter. */
#define SEND_OK(x) std::cout << "OK " << x << std::endl
/* send ERR result to Squid with a string parameter. */
#define SEND_ERR(x) std::cout << "ERR " << x << std::endl
-/* send ERR result to Squid with a string parameter. */
+/* send BH result to Squid with a string parameter. */
#define SEND_BH(x) std::cout << "BH " << x << std::endl
+/* constructs a message to Squid. */
+#define HLP_MSG(text) "message=\"" text "\""
+
/* send TT result to Squid with a string parameter. */
#define SEND_TT(x) std::cout << "TT " << x << std::endl
#endif /* __SQUID_HELPERS_DEFINES_H */
_______________________________________________
squid-dev mailing list
[email protected]
http://lists.squid-cache.org/listinfo/squid-dev