src/server/safs/ldap.c

changeset 464
0a29110b94ec
child 465
d22ff46c171c
equal deleted inserted replaced
463:4fd523fff13b 464:0a29110b94ec
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;
44 } else if(!strcmp(str, "children")) {
45 return LDAP_SCOPE_CHILDREN;
46 }
47 return -1;
48 }
49
50 int ldap_query_saf(pblock *pb, Session *sn, Request *rq) {
51 char *resource_name = pblock_findval("resource", pb);
52 char *basedn = pblock_findval("basedn", pb);
53 char *binddn = pblock_findval("bindnd", pb);
54 char *bindpw = pblock_findval("bindpw", pb);
55 char *ldap_query = pblock_findval("query", pb);
56 char *empty_query_error = pblock_findval("empty_query_error", pb);
57 char *empty_result_error = pblock_findval("empty_result_error", pb);
58 char *scope_str = pblock_findval("scope", pb);
59 char *timeout_str = pblock_findval("timeout", pb);
60 char *sizelimit_str = pblock_findval("sizelimit", pb);
61
62 int status_empty_query = WS_SAFS_LDAP_EMPTY_QUERY_ERROR;
63 int status_empty_result = WS_SAFS_LDAP_EMPTY_RESULT_ERROR;
64
65 if(empty_query_error) {
66 int64_t status = 0;
67 util_strtoint(empty_query_error, &status);
68 if(status < 200 || status > 999) {
69 log_ereport(LOG_MISCONFIG, "ldap-query: empty_query_error parameter must be an integer between 200 and 999");
70 return REQ_ABORTED;
71 }
72 status_empty_query = status;
73 }
74 if(empty_result_error) {
75 int64_t status = 0;
76 util_strtoint(empty_result_error, &status);
77 if(status < 200 || status > 999) {
78 log_ereport(LOG_MISCONFIG, "ldap-query: empty_result_error parameter must be an integer between 200 and 999");
79 return REQ_ABORTED;
80 }
81 status_empty_result = status;
82 }
83
84 // should we sent an empty response in case of an empty query/result
85 // or the standard error message?
86 WSBool empty_query_response = status_empty_query < 300 ? TRUE : FALSE;
87 WSBool empty_result_response = status_empty_result < 300 ? TRUE : FALSE;
88
89 int scope = WS_SAFS_LDAP_DEFAULT_SCOPE;
90 if(scope_str) {
91 scope = get_ldap_scope(scope_str);
92 if(scope < 0) {
93 log_ereport(LOG_MISCONFIG, "ldap-query: unknown scope %s", scope_str);
94 return REQ_ABORTED;
95 }
96 }
97 int timeout = WS_SAFS_LDAP_DEFAULT_TIMEOUT;
98 if(timeout_str) {
99 int64_t t;
100 if(util_strtoint(timeout_str, &t)) {
101 if(t < 0 || t > WS_SAFS_LDAP_MAX_TIMEOUT) {
102 log_ereport(LOG_MISCONFIG, "ldap-query: timeout out of range");
103 return REQ_ABORTED;
104 }
105 timeout = t;
106 } else {
107 log_ereport(LOG_MISCONFIG, "ldap-query: timeout %s is not a number", timeout_str);
108 }
109 }
110 int sizelimit = WS_SAFS_LDAP_DEFAULT_SIZELIMIT;
111 if(timeout_str) {
112 int64_t v;
113 if(util_strtoint(timeout_str, &v)) {
114 if(v > INT_MAX) {
115 log_ereport(LOG_MISCONFIG, "ldap-query: sizelimit out of range");
116 return REQ_ABORTED;
117 }
118 sizelimit = v;
119 } else {
120 log_ereport(LOG_MISCONFIG, "ldap-query: sizelimit %s is not a number", timeout_str);
121 }
122 }
123
124
125 if(!resource_name) {
126 log_ereport(LOG_MISCONFIG, "ldap-query: missing resource parameter");
127 return REQ_ABORTED;
128 }
129 if(!basedn) {
130 log_ereport(LOG_MISCONFIG, "ldap-query: missing basedn parameter");
131 return REQ_ABORTED;
132 }
133
134 if(!ldap_query) {
135 // alternatively get query from rq->vars
136 ldap_query = pblock_findval("ldap_query", rq->vars);
137 if(!ldap_query) {
138 // no ldap query
139 protocol_status(sn, rq, status_empty_query, NULL);
140 if(empty_query_response) {
141 pblock_nvinsert("content-length", "0", rq->srvhdrs);
142 http_start_response(sn, rq);
143 }
144 return REQ_PROCEED;
145 }
146 }
147
148 // get the resource
149 ResourceData *resdata = resourcepool_lookup(sn, rq, resource_name, 0);
150 if(!resdata) {
151 log_ereport(LOG_FAILURE, "ldap-query: cannot get resource %s", resource_name);
152 return REQ_ABORTED;
153 }
154 LDAP *ldap = resdata->data;
155
156 // optionally, use binddn
157 if(binddn) {
158 struct berval *server_cred;
159 if(ws_ldap_bind(ldap, binddn, bindpw ? bindpw : "", &server_cred) != LDAP_SUCCESS) {
160 log_ereport(LOG_FAILURE, "ldap-query: resource %s: cannot bind %s", resource_name, binddn);
161 resourcepool_free(sn, rq, resdata);
162 return REQ_ABORTED;
163 }
164 }
165
166
167 // search
168 LDAPMessage *result;
169 struct timeval ts;
170 ts.tv_sec = timeout;
171 ts.tv_usec = 0;
172 int r = ldap_search_ext_s(
173 ldap,
174 basedn,
175 LDAP_SCOPE_SUBTREE,
176 ldap_query,
177 NULL,
178 0,
179 NULL, // server controls
180 NULL, // client controls
181 &ts,
182 sizelimit, // size limit
183 &result);
184
185 if(r != LDAP_SUCCESS) {
186 if(result) {
187 ldap_msgfree(result);
188 }
189 log_ereport(LOG_FAILURE, "ldap-query: ldap error: %s", ldap_err2string(r));
190 return REQ_ABORTED;
191 }
192
193
194 // send http header
195 protocol_status(sn, rq, 200, NULL);
196
197
198 LDAPMessage *msg = ldap_first_entry(ldap, result);
199 if(!msg) {
200 protocol_status(sn, rq, status_empty_result, NULL);
201 if(empty_result_response) {
202 pblock_nvinsert("content-length", "0", rq->srvhdrs);
203 }
204 } else {
205 protocol_status(sn, rq, 200, NULL);
206 }
207 http_start_response(sn, rq);
208
209 while(msg) {
210 // dn
211 char *dn = ldap_get_dn(ldap, msg);
212 if(dn) {
213 net_printf(sn->csd, "dn: %s\n", dn);
214 ldap_memfree(dn);
215 }
216
217 // get attributes
218 BerElement *ber = NULL;
219 char *attribute = attribute=ldap_first_attribute(ldap, msg, &ber);
220 while(attribute != NULL) {
221 struct berval **values = ldap_get_values_len(ldap, msg, attribute);
222 if(values) {
223 int count = ldap_count_values_len(values);
224 for(int i=0;i<count;i++) {
225 cxstring value = cx_strn(values[i]->bv_val, values[i]->bv_len);
226 net_printf(sn->csd, "%s: %.*s\n", attribute, (int)value.length, value.ptr);
227 }
228 ldap_value_free_len(values);
229 }
230 ldap_memfree(attribute);
231 attribute = ldap_next_attribute(ldap, msg, ber);
232 }
233 if(ber) {
234 ber_free(ber, 0);
235 }
236 net_printf(sn->csd, "\n");
237 msg = ldap_next_entry(ldap, msg);
238 }
239 ldap_msgfree(result);
240
241
242 return REQ_PROCEED;
243 }

mercurial