#include "ldap.h"
#include <time.h>
#include <limits.h>
#include "../util/util.h"
static int get_ldap_scope(
const char *str) {
if(!strcmp(str,
"base")) {
return LDAP_SCOPE_BASE;
}
else if(!strcmp(str,
"onelevel")) {
return LDAP_SCOPE_ONELEVEL;
}
else if(!strcmp(str,
"subtree")) {
return LDAP_SCOPE_SUBTREE;
}
else if(!strcmp(str,
"children")) {
return LDAP_SCOPE_CHILDREN;
}
return -
1;
}
int service_ldap_search(pblock *pb, Session *sn, Request *rq) {
char *resource_name = pblock_findval(
"resource", pb);
char *basedn = pblock_findval(
"basedn", pb);
char *binddn = pblock_findval(
"bindnd", pb);
char *bindpw = pblock_findval(
"bindpw", pb);
char *filter = pblock_findval(
"filter", pb);
char *empty_query_error = pblock_findval(
"empty_filter_error", pb);
char *empty_result_error = pblock_findval(
"empty_result_error", pb);
char *scope_str = pblock_findval(
"scope", pb);
char *timeout_str = pblock_findval(
"timeout", pb);
char *sizelimit_str = pblock_findval(
"sizelimit", pb);
int status_empty_filter =
WS_SAFS_LDAP_EMPTY_FILTER_ERROR;
int status_empty_result =
WS_SAFS_LDAP_EMPTY_RESULT_ERROR;
if(empty_query_error) {
int64_t status =
0;
util_strtoint(empty_query_error, &status);
if(status <
200 || status >
999) {
log_ereport(
LOG_MISCONFIG,
"ldap-search: empty_query_error parameter must be an integer between 200 and 999");
return REQ_ABORTED;
}
status_empty_filter = status;
}
if(empty_result_error) {
int64_t status =
0;
util_strtoint(empty_result_error, &status);
if(status <
200 || status >
999) {
log_ereport(
LOG_MISCONFIG,
"ldap-search: empty_result_error parameter must be an integer between 200 and 999");
return REQ_ABORTED;
}
status_empty_result = status;
}
WSBool empty_query_response = status_empty_filter <
300 ?
TRUE :
FALSE;
WSBool empty_result_response = status_empty_result <
300 ?
TRUE :
FALSE;
int scope =
WS_SAFS_LDAP_DEFAULT_SCOPE;
if(scope_str) {
scope = get_ldap_scope(scope_str);
if(scope <
0) {
log_ereport(
LOG_MISCONFIG,
"ldap-search: unknown scope %s", scope_str);
return REQ_ABORTED;
}
}
int timeout =
WS_SAFS_LDAP_DEFAULT_TIMEOUT;
if(timeout_str) {
int64_t t;
if(util_strtoint(timeout_str, &t)) {
if(t <
0 || t >
WS_SAFS_LDAP_MAX_TIMEOUT) {
log_ereport(
LOG_MISCONFIG,
"ldap-search: timeout out of range");
return REQ_ABORTED;
}
timeout = t;
}
else {
log_ereport(
LOG_MISCONFIG,
"ldap-search: timeout %s is not a number", timeout_str);
}
}
int sizelimit =
WS_SAFS_LDAP_DEFAULT_SIZELIMIT;
if(sizelimit_str) {
int64_t v;
if(util_strtoint(sizelimit_str, &v)) {
if(v >
INT_MAX) {
log_ereport(
LOG_MISCONFIG,
"ldap-search: sizelimit out of range");
return REQ_ABORTED;
}
sizelimit = v;
}
else {
log_ereport(
LOG_MISCONFIG,
"ldap-search: sizelimit %s is not a number", timeout_str);
}
}
if(!resource_name) {
log_ereport(
LOG_MISCONFIG,
"ldap-search: missing resource parameter");
return REQ_ABORTED;
}
if(!basedn) {
log_ereport(
LOG_MISCONFIG,
"ldap-search: missing basedn parameter");
return REQ_ABORTED;
}
if(!filter) {
filter = pblock_findval(
"ldap_filter", rq->vars);
log_ereport(
LOG_DEBUG,
"ldap-search: no filter parameter, rq.vars ldap_filter: %s", filter);
if(!filter) {
protocol_status(sn, rq, status_empty_filter,
NULL);
if(empty_query_response) {
pblock_nvinsert(
"content-length",
"0", rq->srvhdrs);
http_start_response(sn, rq);
}
else {
log_ereport(
LOG_FAILURE,
"ldap-search: no filter specified");
}
return REQ_PROCEED;
}
}
ResourceData *resdata = resourcepool_lookup(sn, rq, resource_name,
0);
if(!resdata) {
log_ereport(
LOG_FAILURE,
"ldap-search: cannot get resource %s", resource_name);
return REQ_ABORTED;
}
LDAP *ldap = resdata->data;
if(binddn) {
struct berval *server_cred;
if(ws_ldap_bind(ldap, binddn, bindpw ? bindpw :
"", &server_cred) !=
LDAP_SUCCESS) {
log_ereport(
LOG_FAILURE,
"ldap-search: resource %s: cannot bind %s", resource_name, binddn);
resourcepool_free(sn, rq, resdata);
return REQ_ABORTED;
}
}
LDAPMessage *result;
struct timeval ts;
ts.tv_sec = timeout;
ts.tv_usec =
0;
int r = ldap_search_ext_s(
ldap,
basedn,
LDAP_SCOPE_SUBTREE,
filter,
NULL,
0,
NULL,
NULL,
&ts,
sizelimit,
&result);
if(r !=
LDAP_SUCCESS) {
if(result) {
ldap_msgfree(result);
}
log_ereport(
LOG_FAILURE,
"ldap-search: ldap error: %s", ldap_err2string(r));
return REQ_ABORTED;
}
protocol_status(sn, rq,
200,
NULL);
LDAPMessage *msg = ldap_first_entry(ldap, result);
if(!msg) {
protocol_status(sn, rq, status_empty_result,
NULL);
if(empty_result_response) {
pblock_nvinsert(
"content-length",
"0", rq->srvhdrs);
}
}
else {
protocol_status(sn, rq,
200,
NULL);
}
http_start_response(sn, rq);
while(msg) {
char *dn = ldap_get_dn(ldap, msg);
if(dn) {
net_printf(sn->csd,
"dn: %s\n", dn);
ldap_memfree(dn);
}
BerElement *ber =
NULL;
char *attribute = attribute=ldap_first_attribute(ldap, msg, &ber);
while(attribute !=
NULL) {
struct berval **values = ldap_get_values_len(ldap, msg, attribute);
if(values) {
int count = ldap_count_values_len(values);
for(
int i=
0;i<count;i++) {
cxstring value = cx_strn(values[i]->bv_val, values[i]->bv_len);
net_printf(sn->csd,
"%s: %.*s\n", attribute, (
int)value.length, value.ptr);
}
ldap_value_free_len(values);
}
ldap_memfree(attribute);
attribute = ldap_next_attribute(ldap, msg, ber);
}
if(ber) {
ber_free(ber,
0);
}
net_printf(sn->csd,
"\n");
msg = ldap_next_entry(ldap, msg);
}
ldap_msgfree(result);
return REQ_PROCEED;
}