46 #define LDAP_DEPRECATED 1
56 #if _SQUID_WINDOWS_ && !_SQUID_CYGWIN_
58 #define snprintf _snprintf
62 #define LDAPAPI __cdecl
65 #ifndef LDAP_OPT_X_TLS
66 #define LDAP_OPT_X_TLS 0x6000
71 #undef ldap_start_tls_s
73 #define LDAP_START_TLS_S "ldap_start_tls_sW"
74 typedef WINLDAPAPI
ULONG(LDAPAPI * PFldap_start_tls_s) (IN PLDAP, OUT PULONG, OUT LDAPMessage **, IN PLDAPControlW *, IN PLDAPControlW *);
76 #define LDAP_START_TLS_S "ldap_start_tls_sA"
77 typedef WINLDAPAPI
ULONG(LDAPAPI * PFldap_start_tls_s) (IN PLDAP, OUT PULONG, OUT LDAPMessage **, IN PLDAPControlA *, IN PLDAPControlA *);
79 PFldap_start_tls_s Win32_ldap_start_tls_s;
80 #define ldap_start_tls_s(l,s,c) Win32_ldap_start_tls_s(l, nullptr, nullptr,s,c)
94 #define PROGRAM_NAME "ext_ldap_group_acl"
95 #define PROGRAM_VERSION "2.18"
110 #if defined(NETSCAPE_SSL)
111 static char *sslpath =
nullptr;
112 static int sslinit = 0;
123 static int searchLDAP(LDAP *
ld,
char *group,
char *user,
char *extension_dn);
129 #ifndef LDAP_NO_ATTRS
130 #define LDAP_NO_ATTRS "1.1"
133 #if defined(LDAP_API_VERSION) && LDAP_API_VERSION > 1823
138 ldap_get_option(
ld, LDAP_OPT_ERROR_NUMBER, &err);
144 ldap_set_option(
ld, LDAP_OPT_DEREF, &deref);
149 int *value =
static_cast<int*
>(referrals ? LDAP_OPT_ON :LDAP_OPT_OFF);
150 ldap_set_option(
ld, LDAP_OPT_REFERRALS, value);
155 ldap_set_option(
ld, LDAP_OPT_TIMELIMIT, &aTimeLimit);
160 #if defined(LDAP_OPT_NETWORK_TIMEOUT)
162 tv.tv_sec = aTimeLimit;
164 ldap_set_option(
ld, LDAP_OPT_NETWORK_TIMEOUT, &tv);
165 #elif defined(LDAP_X_OPT_CONNECT_TIMEOUT)
167 ldap_set_option(
ld, LDAP_X_OPT_CONNECT_TIMEOUT, &aTimeLimit);
185 ld->ld_deref = deref;
191 ld->ld_options |= ~LDAP_OPT_REFERRALS;
193 ld->ld_options &= ~LDAP_OPT_REFERRALS;
203 fprintf(stderr,
"WARNING: Connect timeouts not supported in your LDAP library\n");
213 #ifdef LDAP_API_FEATURE_X_OPENLDAP
214 #if LDAP_VENDOR_VERSION > 194
215 #define HAS_URI_SUPPORT 1
223 char *user, *group, *extension_dn =
nullptr;
226 int tryagain = 0, rc;
227 int port = LDAP_PORT;
228 int use_extension_dn = 0;
230 int strip_kerberos_realm = 0;
232 setbuf(stdout,
nullptr);
234 while (argc > 1 && argv[1][0] ==
'-') {
235 const char *value =
"";
236 char option = argv[1][1];
248 if (strlen(argv[1]) > 2) {
250 }
else if (argc > 2) {
263 fprintf(stderr,
"FATAL: Your LDAP library does not have URI support\n");
269 int len = strlen(
ldapServer) + 1 + strlen(value) + 1;
270 char *newhost =
static_cast<char*
>(
xmalloc(len));
271 snprintf(newhost, len,
"%s %s",
ldapServer, value);
294 if (strcmp(value,
"base") == 0)
296 else if (strcmp(value,
"one") == 0)
298 else if (strcmp(value,
"sub") == 0)
301 fprintf(stderr,
PROGRAM_NAME ": FATAL: Unknown search scope '%s'\n", value);
306 #if defined(NETSCAPE_SSL)
308 if (
port == LDAP_PORT)
311 fprintf(stderr,
PROGRAM_NAME ": FATAL: -E unsupported with this LDAP library\n");
322 if (strcmp(value,
"never") == 0)
324 else if (strcmp(value,
"always") == 0)
326 else if (strcmp(value,
"search") == 0)
328 else if (strcmp(value,
"find") == 0)
331 fprintf(stderr,
PROGRAM_NAME ": FATAL: Unknown alias dereference method '%s'\n", value);
355 switch (atoi(value)) {
363 fprintf(stderr,
"FATAL: Protocol version should be 2 or 3\n");
368 if (
version == LDAP_VERSION2) {
369 fprintf(stderr,
"FATAL: TLS (-Z) is incompatible with version %d\n",
381 use_extension_dn = 1;
387 strip_kerberos_realm = 1;
390 fprintf(stderr,
PROGRAM_NAME ": FATAL: Unknown command line option '%c'\n", option);
396 char *value = argv[1];
398 int len = strlen(
ldapServer) + 1 + strlen(value) + 1;
399 char *newhost =
static_cast<char*
>(
xmalloc(len));
400 snprintf(newhost, len,
"%s %s",
ldapServer, value);
415 fprintf(stderr,
"Usage: " PROGRAM_NAME " -b basedn -f filter [options] ldap_server_name\n\n");
416 fprintf(stderr,
"\t-b basedn (REQUIRED)\tbase dn under where to search for groups\n");
417 fprintf(stderr,
"\t-f filter (REQUIRED)\tgroup search filter pattern. %%u = user,\n\t\t\t\t%%v = group\n");
418 fprintf(stderr,
"\t-B basedn (REQUIRED)\tbase dn under where to search for users\n");
419 fprintf(stderr,
"\t-F filter (REQUIRED)\tuser search filter pattern. %%s = login\n");
420 fprintf(stderr,
"\t-s base|one|sub\t\tsearch scope\n");
421 fprintf(stderr,
"\t-D binddn\t\tDN to bind as to perform searches\n");
422 fprintf(stderr,
"\t-w bindpasswd\t\tpassword for binddn\n");
423 fprintf(stderr,
"\t-W secretfile\t\tread password for binddn from file secretfile\n");
425 fprintf(stderr,
"\t-H URI\t\t\tLDAPURI (defaults to ldap://localhost)\n");
427 fprintf(stderr,
"\t-h server\t\tLDAP server (defaults to localhost)\n");
428 fprintf(stderr,
"\t-p port\t\t\tLDAP server port (defaults to %d)\n", LDAP_PORT);
429 fprintf(stderr,
"\t-P\t\t\tpersistent LDAP connection\n");
430 #if defined(NETSCAPE_SSL)
431 fprintf(stderr,
"\t-E sslcertpath\t\tenable LDAP over SSL\n");
433 fprintf(stderr,
"\t-c timeout\t\tconnect timeout\n");
434 fprintf(stderr,
"\t-t timelimit\t\tsearch time limit\n");
435 fprintf(stderr,
"\t-R\t\t\tdo not follow referrals\n");
436 fprintf(stderr,
"\t-a never|always|search|find\n\t\t\t\twhen to dereference aliases\n");
438 fprintf(stderr,
"\t-v 2|3\t\t\tLDAP version\n");
439 fprintf(stderr,
"\t-Z\t\t\tTLS encrypt the LDAP connection, requires\n\t\t\t\tLDAP version 3\n");
441 fprintf(stderr,
"\t-g\t\t\tfirst query parameter is base DN extension\n\t\t\t\tfor this query\n");
442 fprintf(stderr,
"\t-S\t\t\tStrip NT domain from usernames\n");
443 fprintf(stderr,
"\t-K\t\t\tStrip Kerberos realm from usernames\n");
444 fprintf(stderr,
"\t-d\t\t\tenable debug mode\n");
445 fprintf(stderr,
"\n");
446 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");
455 HMODULE WLDAP32Handle;
457 WLDAP32Handle = GetModuleHandle(
"wldap32");
458 if ((Win32_ldap_start_tls_s = (PFldap_start_tls_s) GetProcAddress(WLDAP32Handle, LDAP_START_TLS_S)) ==
NULL) {
459 fprintf(stderr,
PROGRAM_NAME ": FATAL: TLS (-Z) not supported on this platform.\n");
467 if (!strchr(buf,
'\n')) {
469 fprintf(stderr,
"%s: ERROR: Input Too large: %s\n", argv[0], buf);
470 while (fgets(buf,
sizeof(buf), stdin)) {
471 fprintf(stderr,
"%s: ERROR: Input Too large..: %s\n", argv[0], buf);
472 if (strchr(buf,
'\n') !=
nullptr)
478 user = strtok(buf,
" \n");
480 debug(
"%s: Invalid request: No Username given\n", argv[0]);
486 char *u = strrchr(user,
'\\');
488 u = strrchr(user,
'/');
490 u = strrchr(user,
'+');
494 if (strip_kerberos_realm) {
495 char *u = strchr(user,
'@');
500 if (use_extension_dn) {
501 extension_dn = strtok(
nullptr,
" \n");
503 debug(
"%s: Invalid request: Extension DN configured, but none sent.\n", argv[0]);
509 const char *broken =
nullptr;
510 while (!found && user && (group = strtok(
nullptr,
" \n")) !=
nullptr) {
518 if (rc != LDAP_SUCCESS) {
519 broken =
HLP_MSG(
"Unable to connect to LDAP server");
520 fprintf(stderr,
"%s: ERROR: Unable to connect to LDAPURI:%s\n", argv[0],
ldapServer);
527 if (!sslinit && (ldapssl_client_init(sslpath,
nullptr) != LDAP_SUCCESS)) {
528 fprintf(stderr,
"FATAL: Unable to initialise SSL with cert path %s\n", sslpath);
534 fprintf(stderr,
"FATAL: Unable to connect to SSL LDAP server: %s port:%d\n",
541 broken =
HLP_MSG(
"Unable to connect to LDAP server");
542 fprintf(stderr,
"ERROR: %s:%s port:%d\n", broken,
ldapServer,
port);
552 if (ldap_set_option(
ld, LDAP_OPT_PROTOCOL_VERSION, &
version) != LDAP_SUCCESS) {
553 broken =
HLP_MSG(
"Could not set LDAP_OPT_PROTOCOL_VERSION");
554 fprintf(stderr,
"ERROR: %s %d\n", broken,
version);
560 #ifdef LDAP_OPT_X_TLS
561 if (
version != LDAP_VERSION3) {
562 fprintf(stderr,
"FATAL: TLS requires LDAP version 3\n");
564 }
else if (ldap_start_tls_s(
ld,
nullptr,
nullptr) != LDAP_SUCCESS) {
565 broken =
HLP_MSG(
"Could not Activate TLS connection");
566 fprintf(stderr,
"ERROR: %s\n", broken);
572 fprintf(stderr,
"FATAL: TLS not supported with your LDAP library\n");
582 if (rc != LDAP_SUCCESS) {
583 broken =
HLP_MSG(
"could not bind");
584 fprintf(stderr,
PROGRAM_NAME ": WARNING: %s to binddn '%s'\n", broken, ldap_err2string(rc));
590 debug(
"Connected OK\n");
592 int searchResult =
searchLDAP(
ld, group, user, extension_dn);
593 if (searchResult == 0) {
596 }
else if (searchResult < 0) {
603 broken =
HLP_MSG(
"LDAP search error");
631 std::stringstream str;
632 for (
const auto &c : src) {
638 str <<
'\\' <<
asHex(c).minDigits(2);
648 build_filter(std::string &filter,
const char *templ,
const char *user,
const char *group)
650 std::stringstream str;
667 fprintf(stderr,
"ERROR: Unknown filter template string %%%c\n", *templ);
692 std::stringstream searchBaseStream;
693 if (extension_dn && *extension_dn)
694 searchBaseStream << extension_dn <<
",";
695 searchBaseStream << base_dn;
696 return searchBaseStream.str();
701 if (result == LDAP_SUCCESS)
703 if (
noreferrals && result == LDAP_PARTIAL_RESULTS) {
709 std::cerr <<
PROGRAM_NAME <<
": WARNING: LDAP search error '" <<
710 ldap_err2string(result) <<
"'" << std::endl;
711 #if defined(NETSCAPE_SSL)
712 if (sslpath && ((result == LDAP_SERVER_DOWN) || (result == LDAP_CONNECT_ERROR))) {
713 int sslerr = PORT_GetError();
714 std::cerr <<
PROGRAM_NAME <<
": WARNING: SSL error " << sslerr <<
" (" <<
715 ldapssl_err2string(sslerr) <<
")" << std::endl;
721 typedef const std::unique_ptr<LDAPMessage, decltype(&ldap_msgfree)>
LdapResult;
727 LDAPMessage *res =
nullptr;
733 std::cerr <<
PROGRAM_NAME <<
": ERROR: Failed to construct LDAP search filter. filter=\"" <<
734 filter.c_str() <<
"\", user=\"" << member <<
"\", group=\"" << group <<
"\"" << std::endl;
737 debug(
"group filter '%s', searchbase '%s'\n", filter.c_str(), searchbase.c_str());
739 rc = ldap_search_s(
ld, searchbase.c_str(),
searchscope, filter.c_str(), searchattr, 1, &res);
744 return ldap_first_entry(
ld, ldapRes.get()) ? 0 : 1;
750 size_t start_pos = 0;
751 while ((start_pos = formatted.find(
"%s", start_pos)) != std::string::npos) {
752 formatted.replace(start_pos, 2, value);
763 LDAPMessage *res =
nullptr;
768 const std::string searchbase =
build_searchbase(extension_dn, current_userdn);
773 debug(
"user filter '%s', searchbase '%s'\n", filter.c_str(), searchbase.c_str());
774 rc = ldap_search_s(
ld, searchbase.c_str(),
searchscope, filter.c_str(), searchattr, 1, &res);
778 entry = ldap_first_entry(
ld, ldapRes.get());
780 std::cerr <<
PROGRAM_NAME <<
": WARNING: User '" << login <<
781 " not found in '" << searchbase.c_str() <<
"'" << std::endl;
784 userdn = ldap_get_dn(
ld, entry);
789 std::stringstream str;
791 if (extension_dn && *extension_dn)
792 str << extension_dn <<
", ";
793 str << current_userdn;
807 if (!(f = fopen(filename,
"r"))) {
808 fprintf(stderr,
PROGRAM_NAME ": ERROR: Can not read secret file %s\n", filename);
811 if (!fgets(buf,
sizeof(buf) - 1, f)) {
812 fprintf(stderr,
PROGRAM_NAME ": ERROR: Secret file %s is empty\n", filename);
817 if ((e = strrchr(buf,
'\n')))
819 if ((e = strrchr(buf,
'\r')))
824 fprintf(stderr,
PROGRAM_NAME ": ERROR: can not allocate memory\n");