Tue, 24 Feb 2026 12:28:58 +0100
fix build on Solaris 10
| 464 | 1 | /* |
| 2 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. | |
| 3 | * | |
| 4 | * Copyright 2023 Olaf Wintermann. All rights reserved. | |
| 5 | * | |
| 6 | * Redistribution and use in source and binary forms, with or without | |
| 7 | * modification, are permitted provided that the following conditions are met: | |
| 8 | * | |
| 9 | * 1. Redistributions of source code must retain the above copyright | |
| 10 | * notice, this list of conditions and the following disclaimer. | |
| 11 | * | |
| 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 13 | * notice, this list of conditions and the following disclaimer in the | |
| 14 | * documentation and/or other materials provided with the distribution. | |
| 15 | * | |
| 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
| 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | |
| 20 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
| 21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
| 22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
| 23 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
| 24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
| 25 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| 26 | * POSSIBILITY OF SUCH DAMAGE. | |
| 27 | */ | |
| 28 | ||
| 29 | #include "ldap.h" | |
| 30 | ||
| 31 | #include <time.h> | |
| 32 | #include <limits.h> | |
| 33 | ||
| 34 | #include "../util/util.h" | |
| 35 | ||
| 36 | static int get_ldap_scope(const char *str) { | |
| 37 | // search scope: base, onelevel, subtree, children | |
| 38 | if(!strcmp(str, "base")) { | |
| 39 | return LDAP_SCOPE_BASE; | |
| 40 | } else if(!strcmp(str, "onelevel")) { | |
| 41 | return LDAP_SCOPE_ONELEVEL; | |
| 42 | } else if(!strcmp(str, "subtree")) { | |
| 43 | return LDAP_SCOPE_SUBTREE; | |
|
702
ee80191310ca
fix build on Solaris 10
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
465
diff
changeset
|
44 | } |
|
ee80191310ca
fix build on Solaris 10
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
465
diff
changeset
|
45 | #ifdef LDAP_SCOPE_CHILDREN |
|
ee80191310ca
fix build on Solaris 10
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
465
diff
changeset
|
46 | else if(!strcmp(str, "children")) { |
| 464 | 47 | return LDAP_SCOPE_CHILDREN; |
| 48 | } | |
|
702
ee80191310ca
fix build on Solaris 10
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
465
diff
changeset
|
49 | #endif |
| 464 | 50 | return -1; |
| 51 | } | |
| 52 | ||
|
465
d22ff46c171c
rename ldap-query to ldap-search, rename query parameter to filter
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
464
diff
changeset
|
53 | int service_ldap_search(pblock *pb, Session *sn, Request *rq) { |
| 464 | 54 | char *resource_name = pblock_findval("resource", pb); |
| 55 | char *basedn = pblock_findval("basedn", pb); | |
| 56 | char *binddn = pblock_findval("bindnd", pb); | |
| 57 | char *bindpw = pblock_findval("bindpw", pb); | |
|
465
d22ff46c171c
rename ldap-query to ldap-search, rename query parameter to filter
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
464
diff
changeset
|
58 | char *filter = pblock_findval("filter", pb); |
|
d22ff46c171c
rename ldap-query to ldap-search, rename query parameter to filter
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
464
diff
changeset
|
59 | char *empty_query_error = pblock_findval("empty_filter_error", pb); |
| 464 | 60 | char *empty_result_error = pblock_findval("empty_result_error", pb); |
| 61 | char *scope_str = pblock_findval("scope", pb); | |
| 62 | char *timeout_str = pblock_findval("timeout", pb); | |
| 63 | char *sizelimit_str = pblock_findval("sizelimit", pb); | |
| 64 | ||
|
465
d22ff46c171c
rename ldap-query to ldap-search, rename query parameter to filter
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
464
diff
changeset
|
65 | int status_empty_filter = WS_SAFS_LDAP_EMPTY_FILTER_ERROR; |
| 464 | 66 | int status_empty_result = WS_SAFS_LDAP_EMPTY_RESULT_ERROR; |
| 67 | ||
| 68 | if(empty_query_error) { | |
| 69 | int64_t status = 0; | |
| 70 | util_strtoint(empty_query_error, &status); | |
| 71 | if(status < 200 || status > 999) { | |
|
465
d22ff46c171c
rename ldap-query to ldap-search, rename query parameter to filter
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
464
diff
changeset
|
72 | log_ereport(LOG_MISCONFIG, "ldap-search: empty_query_error parameter must be an integer between 200 and 999"); |
| 464 | 73 | return REQ_ABORTED; |
| 74 | } | |
|
465
d22ff46c171c
rename ldap-query to ldap-search, rename query parameter to filter
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
464
diff
changeset
|
75 | status_empty_filter = status; |
| 464 | 76 | } |
| 77 | if(empty_result_error) { | |
| 78 | int64_t status = 0; | |
| 79 | util_strtoint(empty_result_error, &status); | |
| 80 | if(status < 200 || status > 999) { | |
|
465
d22ff46c171c
rename ldap-query to ldap-search, rename query parameter to filter
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
464
diff
changeset
|
81 | log_ereport(LOG_MISCONFIG, "ldap-search: empty_result_error parameter must be an integer between 200 and 999"); |
| 464 | 82 | return REQ_ABORTED; |
| 83 | } | |
| 84 | status_empty_result = status; | |
| 85 | } | |
| 86 | ||
| 87 | // should we sent an empty response in case of an empty query/result | |
| 88 | // or the standard error message? | |
|
465
d22ff46c171c
rename ldap-query to ldap-search, rename query parameter to filter
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
464
diff
changeset
|
89 | WSBool empty_query_response = status_empty_filter < 300 ? TRUE : FALSE; |
| 464 | 90 | WSBool empty_result_response = status_empty_result < 300 ? TRUE : FALSE; |
| 91 | ||
| 92 | int scope = WS_SAFS_LDAP_DEFAULT_SCOPE; | |
| 93 | if(scope_str) { | |
| 94 | scope = get_ldap_scope(scope_str); | |
| 95 | if(scope < 0) { | |
|
465
d22ff46c171c
rename ldap-query to ldap-search, rename query parameter to filter
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
464
diff
changeset
|
96 | log_ereport(LOG_MISCONFIG, "ldap-search: unknown scope %s", scope_str); |
| 464 | 97 | return REQ_ABORTED; |
| 98 | } | |
| 99 | } | |
| 100 | int timeout = WS_SAFS_LDAP_DEFAULT_TIMEOUT; | |
| 101 | if(timeout_str) { | |
| 102 | int64_t t; | |
| 103 | if(util_strtoint(timeout_str, &t)) { | |
| 104 | if(t < 0 || t > WS_SAFS_LDAP_MAX_TIMEOUT) { | |
|
465
d22ff46c171c
rename ldap-query to ldap-search, rename query parameter to filter
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
464
diff
changeset
|
105 | log_ereport(LOG_MISCONFIG, "ldap-search: timeout out of range"); |
| 464 | 106 | return REQ_ABORTED; |
| 107 | } | |
| 108 | timeout = t; | |
| 109 | } else { | |
|
465
d22ff46c171c
rename ldap-query to ldap-search, rename query parameter to filter
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
464
diff
changeset
|
110 | log_ereport(LOG_MISCONFIG, "ldap-search: timeout %s is not a number", timeout_str); |
| 464 | 111 | } |
| 112 | } | |
| 113 | int sizelimit = WS_SAFS_LDAP_DEFAULT_SIZELIMIT; | |
|
465
d22ff46c171c
rename ldap-query to ldap-search, rename query parameter to filter
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
464
diff
changeset
|
114 | if(sizelimit_str) { |
| 464 | 115 | int64_t v; |
|
465
d22ff46c171c
rename ldap-query to ldap-search, rename query parameter to filter
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
464
diff
changeset
|
116 | if(util_strtoint(sizelimit_str, &v)) { |
| 464 | 117 | if(v > INT_MAX) { |
|
465
d22ff46c171c
rename ldap-query to ldap-search, rename query parameter to filter
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
464
diff
changeset
|
118 | log_ereport(LOG_MISCONFIG, "ldap-search: sizelimit out of range"); |
| 464 | 119 | return REQ_ABORTED; |
| 120 | } | |
| 121 | sizelimit = v; | |
| 122 | } else { | |
|
465
d22ff46c171c
rename ldap-query to ldap-search, rename query parameter to filter
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
464
diff
changeset
|
123 | log_ereport(LOG_MISCONFIG, "ldap-search: sizelimit %s is not a number", timeout_str); |
| 464 | 124 | } |
| 125 | } | |
| 126 | ||
| 127 | ||
| 128 | if(!resource_name) { | |
|
465
d22ff46c171c
rename ldap-query to ldap-search, rename query parameter to filter
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
464
diff
changeset
|
129 | log_ereport(LOG_MISCONFIG, "ldap-search: missing resource parameter"); |
| 464 | 130 | return REQ_ABORTED; |
| 131 | } | |
| 132 | if(!basedn) { | |
|
465
d22ff46c171c
rename ldap-query to ldap-search, rename query parameter to filter
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
464
diff
changeset
|
133 | log_ereport(LOG_MISCONFIG, "ldap-search: missing basedn parameter"); |
| 464 | 134 | return REQ_ABORTED; |
| 135 | } | |
| 136 | ||
|
465
d22ff46c171c
rename ldap-query to ldap-search, rename query parameter to filter
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
464
diff
changeset
|
137 | if(!filter) { |
|
d22ff46c171c
rename ldap-query to ldap-search, rename query parameter to filter
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
464
diff
changeset
|
138 | // alternatively get filter from rq->vars |
|
d22ff46c171c
rename ldap-query to ldap-search, rename query parameter to filter
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
464
diff
changeset
|
139 | filter = pblock_findval("ldap_filter", rq->vars); |
|
d22ff46c171c
rename ldap-query to ldap-search, rename query parameter to filter
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
464
diff
changeset
|
140 | log_ereport(LOG_DEBUG, "ldap-search: no filter parameter, rq.vars ldap_filter: %s", filter); |
|
d22ff46c171c
rename ldap-query to ldap-search, rename query parameter to filter
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
464
diff
changeset
|
141 | if(!filter) { |
|
d22ff46c171c
rename ldap-query to ldap-search, rename query parameter to filter
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
464
diff
changeset
|
142 | // no ldap filter |
|
d22ff46c171c
rename ldap-query to ldap-search, rename query parameter to filter
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
464
diff
changeset
|
143 | protocol_status(sn, rq, status_empty_filter, NULL); |
| 464 | 144 | if(empty_query_response) { |
| 145 | pblock_nvinsert("content-length", "0", rq->srvhdrs); | |
| 146 | http_start_response(sn, rq); | |
|
465
d22ff46c171c
rename ldap-query to ldap-search, rename query parameter to filter
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
464
diff
changeset
|
147 | } else { |
|
d22ff46c171c
rename ldap-query to ldap-search, rename query parameter to filter
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
464
diff
changeset
|
148 | log_ereport(LOG_FAILURE, "ldap-search: no filter specified"); |
| 464 | 149 | } |
| 150 | return REQ_PROCEED; | |
| 151 | } | |
| 152 | } | |
| 153 | ||
| 154 | // get the resource | |
| 155 | ResourceData *resdata = resourcepool_lookup(sn, rq, resource_name, 0); | |
| 156 | if(!resdata) { | |
|
465
d22ff46c171c
rename ldap-query to ldap-search, rename query parameter to filter
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
464
diff
changeset
|
157 | log_ereport(LOG_FAILURE, "ldap-search: cannot get resource %s", resource_name); |
| 464 | 158 | return REQ_ABORTED; |
| 159 | } | |
| 160 | LDAP *ldap = resdata->data; | |
| 161 | ||
| 162 | // optionally, use binddn | |
| 163 | if(binddn) { | |
| 164 | struct berval *server_cred; | |
| 165 | if(ws_ldap_bind(ldap, binddn, bindpw ? bindpw : "", &server_cred) != LDAP_SUCCESS) { | |
|
465
d22ff46c171c
rename ldap-query to ldap-search, rename query parameter to filter
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
464
diff
changeset
|
166 | log_ereport(LOG_FAILURE, "ldap-search: resource %s: cannot bind %s", resource_name, binddn); |
| 464 | 167 | resourcepool_free(sn, rq, resdata); |
| 168 | return REQ_ABORTED; | |
| 169 | } | |
| 170 | } | |
| 171 | ||
| 172 | ||
| 173 | // search | |
| 174 | LDAPMessage *result; | |
| 175 | struct timeval ts; | |
| 176 | ts.tv_sec = timeout; | |
| 177 | ts.tv_usec = 0; | |
| 178 | int r = ldap_search_ext_s( | |
| 179 | ldap, | |
| 180 | basedn, | |
| 181 | LDAP_SCOPE_SUBTREE, | |
|
465
d22ff46c171c
rename ldap-query to ldap-search, rename query parameter to filter
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
464
diff
changeset
|
182 | filter, |
| 464 | 183 | NULL, |
| 184 | 0, | |
| 185 | NULL, // server controls | |
| 186 | NULL, // client controls | |
| 187 | &ts, | |
| 188 | sizelimit, // size limit | |
| 189 | &result); | |
| 190 | ||
| 191 | if(r != LDAP_SUCCESS) { | |
| 192 | if(result) { | |
| 193 | ldap_msgfree(result); | |
| 194 | } | |
|
465
d22ff46c171c
rename ldap-query to ldap-search, rename query parameter to filter
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
464
diff
changeset
|
195 | log_ereport(LOG_FAILURE, "ldap-search: ldap error: %s", ldap_err2string(r)); |
| 464 | 196 | return REQ_ABORTED; |
| 197 | } | |
| 198 | ||
| 199 | ||
| 200 | // send http header | |
| 201 | protocol_status(sn, rq, 200, NULL); | |
| 202 | ||
| 203 | ||
| 204 | LDAPMessage *msg = ldap_first_entry(ldap, result); | |
| 205 | if(!msg) { | |
| 206 | protocol_status(sn, rq, status_empty_result, NULL); | |
| 207 | if(empty_result_response) { | |
| 208 | pblock_nvinsert("content-length", "0", rq->srvhdrs); | |
| 209 | } | |
| 210 | } else { | |
| 211 | protocol_status(sn, rq, 200, NULL); | |
| 212 | } | |
| 213 | http_start_response(sn, rq); | |
| 214 | ||
| 215 | while(msg) { | |
| 216 | // dn | |
| 217 | char *dn = ldap_get_dn(ldap, msg); | |
| 218 | if(dn) { | |
| 219 | net_printf(sn->csd, "dn: %s\n", dn); | |
| 220 | ldap_memfree(dn); | |
| 221 | } | |
| 222 | ||
| 223 | // get attributes | |
| 224 | BerElement *ber = NULL; | |
| 225 | char *attribute = attribute=ldap_first_attribute(ldap, msg, &ber); | |
| 226 | while(attribute != NULL) { | |
| 227 | struct berval **values = ldap_get_values_len(ldap, msg, attribute); | |
| 228 | if(values) { | |
| 229 | int count = ldap_count_values_len(values); | |
| 230 | for(int i=0;i<count;i++) { | |
| 231 | cxstring value = cx_strn(values[i]->bv_val, values[i]->bv_len); | |
| 232 | net_printf(sn->csd, "%s: %.*s\n", attribute, (int)value.length, value.ptr); | |
| 233 | } | |
| 234 | ldap_value_free_len(values); | |
| 235 | } | |
| 236 | ldap_memfree(attribute); | |
| 237 | attribute = ldap_next_attribute(ldap, msg, ber); | |
| 238 | } | |
| 239 | if(ber) { | |
| 240 | ber_free(ber, 0); | |
| 241 | } | |
| 242 | net_printf(sn->csd, "\n"); | |
| 243 | msg = ldap_next_entry(ldap, msg); | |
| 244 | } | |
| 245 | ldap_msgfree(result); | |
| 246 | ||
| 247 | ||
| 248 | return REQ_PROCEED; | |
| 249 | } |