45#define LDAP_DEPRECATED 1
55#if _SQUID_WINDOWS_ && !_SQUID_CYGWIN_
57#define snprintf _snprintf
61#define LDAPAPI __cdecl
65#define LDAP_OPT_X_TLS 0x6000
70#undef ldap_start_tls_s
72#define LDAP_START_TLS_S "ldap_start_tls_sW"
73typedef WINLDAPAPI
ULONG(LDAPAPI * PFldap_start_tls_s) (IN PLDAP, OUT PULONG, OUT LDAPMessage **, IN PLDAPControlW *, IN PLDAPControlW *);
75#define LDAP_START_TLS_S "ldap_start_tls_sA"
76typedef WINLDAPAPI
ULONG(LDAPAPI * PFldap_start_tls_s) (IN PLDAP, OUT PULONG, OUT LDAPMessage **, IN PLDAPControlA *, IN PLDAPControlA *);
78PFldap_start_tls_s Win32_ldap_start_tls_s;
79#define ldap_start_tls_s(l,s,c) Win32_ldap_start_tls_s(l, nullptr, nullptr,s,c)
93#define PROGRAM_NAME "ext_ldap_group_acl"
94#define PROGRAM_VERSION "2.18"
109#if defined(NETSCAPE_SSL)
110static char *sslpath =
nullptr;
111static int sslinit = 0;
122static int searchLDAP(LDAP *
ld,
char *group,
char *user,
char *extension_dn);
129#define LDAP_NO_ATTRS "1.1"
132#if defined(LDAP_API_VERSION) && LDAP_API_VERSION > 1823
137 ldap_get_option(
ld, LDAP_OPT_ERROR_NUMBER, &err);
143 ldap_set_option(
ld, LDAP_OPT_DEREF, &deref);
148 int *value =
static_cast<int*
>(referrals ? LDAP_OPT_ON :LDAP_OPT_OFF);
149 ldap_set_option(
ld, LDAP_OPT_REFERRALS, value);
154 ldap_set_option(
ld, LDAP_OPT_TIMELIMIT, &aTimeLimit);
159#if defined(LDAP_OPT_NETWORK_TIMEOUT)
161 tv.tv_sec = aTimeLimit;
163 ldap_set_option(
ld, LDAP_OPT_NETWORK_TIMEOUT, &tv);
164#elif defined(LDAP_X_OPT_CONNECT_TIMEOUT)
166 ldap_set_option(
ld, LDAP_X_OPT_CONNECT_TIMEOUT, &aTimeLimit);
184 ld->ld_deref = deref;
190 ld->ld_options |= ~LDAP_OPT_REFERRALS;
192 ld->ld_options &= ~LDAP_OPT_REFERRALS;
202 fprintf(stderr,
"WARNING: Connect timeouts not supported in your LDAP library\n");
212#ifdef LDAP_API_FEATURE_X_OPENLDAP
213#if LDAP_VENDOR_VERSION > 194
214#define HAS_URI_SUPPORT 1
222 char *user, *group, *extension_dn =
nullptr;
225 int tryagain = 0, rc;
226 int port = LDAP_PORT;
227 int use_extension_dn = 0;
229 int strip_kerberos_realm = 0;
231 setbuf(stdout,
nullptr);
233 while (argc > 1 && argv[1][0] ==
'-') {
234 const char *value =
"";
235 char option = argv[1][1];
247 if (strlen(argv[1]) > 2) {
249 }
else if (argc > 2) {
262 fprintf(stderr,
"FATAL: Your LDAP library does not have URI support\n");
268 int len = strlen(
ldapServer) + 1 + strlen(value) + 1;
269 char *newhost =
static_cast<char*
>(
xmalloc(len));
270 snprintf(newhost, len,
"%s %s",
ldapServer, value);
293 if (strcmp(value,
"base") == 0)
295 else if (strcmp(value,
"one") == 0)
297 else if (strcmp(value,
"sub") == 0)
300 fprintf(stderr,
PROGRAM_NAME ": FATAL: Unknown search scope '%s'\n", value);
305#if defined(NETSCAPE_SSL)
307 if (
port == LDAP_PORT)
310 fprintf(stderr,
PROGRAM_NAME ": FATAL: -E unsupported with this LDAP library\n");
321 if (strcmp(value,
"never") == 0)
323 else if (strcmp(value,
"always") == 0)
325 else if (strcmp(value,
"search") == 0)
327 else if (strcmp(value,
"find") == 0)
330 fprintf(stderr,
PROGRAM_NAME ": FATAL: Unknown alias dereference method '%s'\n", value);
354 switch (atoi(value)) {
362 fprintf(stderr,
"FATAL: Protocol version should be 2 or 3\n");
367 if (
version == LDAP_VERSION2) {
368 fprintf(stderr,
"FATAL: TLS (-Z) is incompatible with version %d\n",
380 use_extension_dn = 1;
386 strip_kerberos_realm = 1;
389 fprintf(stderr,
PROGRAM_NAME ": FATAL: Unknown command line option '%c'\n", option);
395 char *value = argv[1];
397 int len = strlen(
ldapServer) + 1 + strlen(value) + 1;
398 char *newhost =
static_cast<char*
>(
xmalloc(len));
399 snprintf(newhost, len,
"%s %s",
ldapServer, value);
414 fprintf(stderr,
"Usage: " PROGRAM_NAME " -b basedn -f filter [options] ldap_server_name\n\n");
415 fprintf(stderr,
"\t-b basedn (REQUIRED)\tbase dn under where to search for groups\n");
416 fprintf(stderr,
"\t-f filter (REQUIRED)\tgroup search filter pattern. %%u = user,\n\t\t\t\t%%v = group\n");
417 fprintf(stderr,
"\t-B basedn (REQUIRED)\tbase dn under where to search for users\n");
418 fprintf(stderr,
"\t-F filter (REQUIRED)\tuser search filter pattern. %%s = login\n");
419 fprintf(stderr,
"\t-s base|one|sub\t\tsearch scope\n");
420 fprintf(stderr,
"\t-D binddn\t\tDN to bind as to perform searches\n");
421 fprintf(stderr,
"\t-w bindpasswd\t\tpassword for binddn\n");
422 fprintf(stderr,
"\t-W secretfile\t\tread password for binddn from file secretfile\n");
424 fprintf(stderr,
"\t-H URI\t\t\tLDAPURI (defaults to ldap://localhost)\n");
426 fprintf(stderr,
"\t-h server\t\tLDAP server (defaults to localhost)\n");
427 fprintf(stderr,
"\t-p port\t\t\tLDAP server port (defaults to %d)\n", LDAP_PORT);
428 fprintf(stderr,
"\t-P\t\t\tpersistent LDAP connection\n");
429#if defined(NETSCAPE_SSL)
430 fprintf(stderr,
"\t-E sslcertpath\t\tenable LDAP over SSL\n");
432 fprintf(stderr,
"\t-c timeout\t\tconnect timeout\n");
433 fprintf(stderr,
"\t-t timelimit\t\tsearch time limit\n");
434 fprintf(stderr,
"\t-R\t\t\tdo not follow referrals\n");
435 fprintf(stderr,
"\t-a never|always|search|find\n\t\t\t\twhen to dereference aliases\n");
437 fprintf(stderr,
"\t-v 2|3\t\t\tLDAP version\n");
438 fprintf(stderr,
"\t-Z\t\t\tTLS encrypt the LDAP connection, requires\n\t\t\t\tLDAP version 3\n");
440 fprintf(stderr,
"\t-g\t\t\tfirst query parameter is base DN extension\n\t\t\t\tfor this query\n");
441 fprintf(stderr,
"\t-S\t\t\tStrip NT domain from usernames\n");
442 fprintf(stderr,
"\t-K\t\t\tStrip Kerberos realm from usernames\n");
443 fprintf(stderr,
"\t-d\t\t\tenable debug mode\n");
444 fprintf(stderr,
"\n");
445 fprintf(stderr,
"\tIf you need to bind as a user to perform searches then use the\n\t-D binddn -w bindpasswd or -D binddn -W secretfile options\n\n");
454 HMODULE WLDAP32Handle;
456 WLDAP32Handle = GetModuleHandle(
"wldap32");
457 if ((Win32_ldap_start_tls_s = (PFldap_start_tls_s) GetProcAddress(WLDAP32Handle, LDAP_START_TLS_S)) ==
NULL) {
458 fprintf(stderr,
PROGRAM_NAME ": FATAL: TLS (-Z) not supported on this platform.\n");
466 if (!strchr(buf,
'\n')) {
468 fprintf(stderr,
"%s: ERROR: Input Too large: %s\n", argv[0], buf);
469 while (fgets(buf,
sizeof(buf), stdin)) {
470 fprintf(stderr,
"%s: ERROR: Input Too large..: %s\n", argv[0], buf);
471 if (strchr(buf,
'\n') !=
nullptr)
477 user = strtok(buf,
" \n");
479 debug(
"%s: Invalid request: No Username given\n", argv[0]);
485 char *u = strrchr(user,
'\\');
487 u = strrchr(user,
'/');
489 u = strrchr(user,
'+');
493 if (strip_kerberos_realm) {
494 char *u = strchr(user,
'@');
499 if (use_extension_dn) {
500 extension_dn = strtok(
nullptr,
" \n");
502 debug(
"%s: Invalid request: Extension DN configured, but none sent.\n", argv[0]);
508 const char *broken =
nullptr;
509 while (!found && user && (group = strtok(
nullptr,
" \n")) !=
nullptr) {
517 if (rc != LDAP_SUCCESS) {
518 broken =
HLP_MSG(
"Unable to connect to LDAP server");
519 fprintf(stderr,
"%s: ERROR: Unable to connect to LDAPURI:%s\n", argv[0],
ldapServer);
526 if (!sslinit && (ldapssl_client_init(sslpath,
nullptr) != LDAP_SUCCESS)) {
527 fprintf(stderr,
"FATAL: Unable to initialise SSL with cert path %s\n", sslpath);
533 fprintf(stderr,
"FATAL: Unable to connect to SSL LDAP server: %s port:%d\n",
540 broken =
HLP_MSG(
"Unable to connect to LDAP server");
541 fprintf(stderr,
"ERROR: %s:%s port:%d\n", broken,
ldapServer,
port);
551 if (ldap_set_option(
ld, LDAP_OPT_PROTOCOL_VERSION, &
version) != LDAP_SUCCESS) {
552 broken =
HLP_MSG(
"Could not set LDAP_OPT_PROTOCOL_VERSION");
553 fprintf(stderr,
"ERROR: %s %d\n", broken,
version);
560 if (
version != LDAP_VERSION3) {
561 fprintf(stderr,
"FATAL: TLS requires LDAP version 3\n");
563 }
else if (ldap_start_tls_s(
ld,
nullptr,
nullptr) != LDAP_SUCCESS) {
564 broken =
HLP_MSG(
"Could not Activate TLS connection");
565 fprintf(stderr,
"ERROR: %s\n", broken);
571 fprintf(stderr,
"FATAL: TLS not supported with your LDAP library\n");
581 if (rc != LDAP_SUCCESS) {
582 broken =
HLP_MSG(
"could not bind");
583 fprintf(stderr,
PROGRAM_NAME ": WARNING: %s to binddn '%s'\n", broken, ldap_err2string(rc));
589 debug(
"Connected OK\n");
591 int searchResult =
searchLDAP(
ld, group, user, extension_dn);
592 if (searchResult == 0) {
595 }
else if (searchResult < 0) {
602 broken =
HLP_MSG(
"LDAP search error");
630 std::stringstream str;
631 for (
const auto &c : src) {
637 str << '\\' << std::setfill('0') << std::setw(2) << std::hex << static_cast<int>(c);
647build_filter(std::string &filter,
const char *templ,
const char *user,
const char *group)
649 std::stringstream str;
666 fprintf(stderr,
"ERROR: Unknown filter template string %%%c\n", *templ);
691 std::stringstream searchBaseStream;
692 if (extension_dn && *extension_dn)
693 searchBaseStream << extension_dn <<
",";
694 searchBaseStream << base_dn;
695 return searchBaseStream.str();
700 if (result == LDAP_SUCCESS)
702 if (
noreferrals && result == LDAP_PARTIAL_RESULTS) {
708 std::cerr <<
PROGRAM_NAME <<
": WARNING: LDAP search error '" <<
709 ldap_err2string(result) <<
"'" << std::endl;
710#if defined(NETSCAPE_SSL)
711 if (sslpath && ((result == LDAP_SERVER_DOWN) || (result == LDAP_CONNECT_ERROR))) {
712 int sslerr = PORT_GetError();
713 std::cerr <<
PROGRAM_NAME <<
": WARNING: SSL error " << sslerr <<
" (" <<
714 ldapssl_err2string(sslerr) <<
")" << std::endl;
720typedef const std::unique_ptr<LDAPMessage,
decltype(&ldap_msgfree)>
LdapResult;
726 LDAPMessage *res =
nullptr;
732 std::cerr <<
PROGRAM_NAME <<
": ERROR: Failed to construct LDAP search filter. filter=\"" <<
733 filter.c_str() <<
"\", user=\"" << member <<
"\", group=\"" << group <<
"\"" << std::endl;
736 debug(
"group filter '%s', searchbase '%s'\n", filter.c_str(), searchbase.c_str());
738 rc = ldap_search_s(
ld, searchbase.c_str(),
searchscope, filter.c_str(), searchattr, 1, &res);
743 return ldap_first_entry(
ld, ldapRes.get()) ? 0 : 1;
749 size_t start_pos = 0;
750 while ((start_pos = formatted.find(
"%s", start_pos)) != std::string::npos) {
751 formatted.replace(start_pos, 2, value);
762 LDAPMessage *res =
nullptr;
767 const std::string searchbase =
build_searchbase(extension_dn, current_userdn);
772 debug(
"user filter '%s', searchbase '%s'\n", filter.c_str(), searchbase.c_str());
773 rc = ldap_search_s(
ld, searchbase.c_str(),
searchscope, filter.c_str(), searchattr, 1, &res);
777 entry = ldap_first_entry(
ld, ldapRes.get());
779 std::cerr <<
PROGRAM_NAME <<
": WARNING: User '" << login <<
780 " not found in '" << searchbase.c_str() <<
"'" << std::endl;
783 userdn = ldap_get_dn(
ld, entry);
788 std::stringstream str;
790 if (extension_dn && *extension_dn)
791 str << extension_dn <<
", ";
792 str << current_userdn;
806 if (!(f = fopen(filename,
"r"))) {
807 fprintf(stderr,
PROGRAM_NAME ": ERROR: Can not read secret file %s\n", filename);
810 if (!fgets(buf,
sizeof(buf) - 1, f)) {
811 fprintf(stderr,
PROGRAM_NAME ": ERROR: Secret file %s is empty\n", filename);
816 if ((e = strrchr(buf,
'\n')))
818 if ((e = strrchr(buf,
'\r')))
823 fprintf(stderr,
PROGRAM_NAME ": ERROR: can not allocate memory\n");
#define HELPER_INPUT_BUFFER
void debug(const char *format,...)
static int strip_nt_domain
static std::string ldap_escape_value(const std::string &src)
static int searchLDAP(LDAP *ld, char *group, char *user, char *extension_dn)
static int readSecret(const char *filename)
int main(int argc, char **argv)
static const char * bindpasswd
static const char * userbasedn
static bool ldap_search_ok(const int result)
static void formatWithString(std::string &formatted, const std::string &value)
static bool build_filter(std::string &filter, const char *templ, const char *user, const char *group)
static const char * usersearchfilter
static void squid_ldap_set_connect_timeout(LDAP *ld, int timelimit)
static const char * binddn
static void squid_ldap_set_referrals(LDAP *ld, int referrals)
static std::string build_searchbase(const char *extension_dn, const char *base_dn)
const std::unique_ptr< LDAPMessage, decltype(&ldap_msgfree)> LdapResult
static int connect_timeout
static void squid_ldap_set_aliasderef(LDAP *ld, int deref)
static const char * userdnattr
static const char * searchfilter
static void squid_ldap_memfree(char *p)
static int searchLDAPGroup(LDAP *ld, const char *group, const char *member, const char *extension_dn)
static void squid_ldap_set_timelimit(LDAP *ld, int timelimit)
static const char * basedn
static int squid_ldap_errno(LDAP *ld)
void rfc1738_unescape(char *url)