Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : Infrastructure for async ldap client requests
4 : Copyright (C) Volker Lendecke 2009
5 :
6 : This program is free software; you can redistribute it and/or modify
7 : it under the terms of the GNU General Public License as published by
8 : the Free Software Foundation; either version 3 of the License, or
9 : (at your option) any later version.
10 :
11 : This program is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : GNU General Public License for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with this program. If not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include "includes.h"
21 : #include "tldap.h"
22 : #include "tldap_util.h"
23 : #include "../libcli/security/security.h"
24 : #include "../lib/util/asn1.h"
25 : #include "lib/util/smb_strtox.h"
26 :
27 2 : bool tldap_entry_values(struct tldap_message *msg, const char *attribute,
28 : DATA_BLOB **values, int *num_values)
29 : {
30 0 : struct tldap_attribute *attributes;
31 0 : int i, num_attributes;
32 :
33 2 : if (!tldap_entry_attributes(msg, &attributes, &num_attributes)) {
34 0 : return false;
35 : }
36 :
37 4 : for (i=0; i<num_attributes; i++) {
38 4 : if (strequal(attribute, attributes[i].name)) {
39 2 : break;
40 : }
41 : }
42 2 : if (i == num_attributes) {
43 0 : return false;
44 : }
45 2 : *num_values = attributes[i].num_values;
46 2 : *values = attributes[i].values;
47 2 : return true;
48 : }
49 :
50 2 : bool tldap_get_single_valueblob(struct tldap_message *msg,
51 : const char *attribute, DATA_BLOB *blob)
52 : {
53 0 : int num_values;
54 0 : DATA_BLOB *values;
55 :
56 2 : if (attribute == NULL) {
57 0 : return NULL;
58 : }
59 2 : if (!tldap_entry_values(msg, attribute, &values, &num_values)) {
60 0 : return NULL;
61 : }
62 2 : if (num_values != 1) {
63 0 : return NULL;
64 : }
65 2 : *blob = values[0];
66 2 : return true;
67 : }
68 :
69 2 : char *tldap_talloc_single_attribute(struct tldap_message *msg,
70 : const char *attribute,
71 : TALLOC_CTX *mem_ctx)
72 : {
73 0 : DATA_BLOB val;
74 0 : char *result;
75 0 : size_t len;
76 :
77 2 : if (!tldap_get_single_valueblob(msg, attribute, &val)) {
78 0 : return NULL;
79 : }
80 2 : if (!convert_string_talloc(mem_ctx, CH_UTF8, CH_UNIX,
81 2 : val.data, val.length,
82 : &result, &len)) {
83 0 : return NULL;
84 : }
85 2 : return result;
86 : }
87 :
88 0 : bool tldap_pull_binsid(struct tldap_message *msg, const char *attribute,
89 : struct dom_sid *sid)
90 : {
91 0 : DATA_BLOB val;
92 0 : ssize_t ret;
93 :
94 0 : if (!tldap_get_single_valueblob(msg, attribute, &val)) {
95 0 : return false;
96 : }
97 0 : ret = sid_parse(val.data, val.length, sid);
98 0 : return (ret != -1);
99 : }
100 :
101 0 : bool tldap_pull_guid(struct tldap_message *msg, const char *attribute,
102 : struct GUID *guid)
103 : {
104 0 : DATA_BLOB val;
105 :
106 0 : if (!tldap_get_single_valueblob(msg, attribute, &val)) {
107 0 : return false;
108 : }
109 0 : return NT_STATUS_IS_OK(GUID_from_data_blob(&val, guid));
110 : }
111 :
112 0 : static bool tldap_add_blob_vals(TALLOC_CTX *mem_ctx, struct tldap_mod *mod,
113 : DATA_BLOB *newvals, int num_newvals)
114 : {
115 0 : int num_values = talloc_array_length(mod->values);
116 0 : int i;
117 0 : DATA_BLOB *tmp;
118 :
119 0 : tmp = talloc_realloc(mem_ctx, mod->values, DATA_BLOB,
120 : num_values + num_newvals);
121 0 : if (tmp == NULL) {
122 0 : return false;
123 : }
124 0 : mod->values = tmp;
125 :
126 0 : for (i=0; i<num_newvals; i++) {
127 0 : mod->values[i+num_values].data = (uint8_t *)talloc_memdup(
128 : mod->values, newvals[i].data, newvals[i].length);
129 0 : if (mod->values[i+num_values].data == NULL) {
130 0 : return false;
131 : }
132 0 : mod->values[i+num_values].length = newvals[i].length;
133 : }
134 0 : mod->num_values = num_values + num_newvals;
135 0 : return true;
136 : }
137 :
138 0 : bool tldap_add_mod_blobs(TALLOC_CTX *mem_ctx,
139 : struct tldap_mod **pmods, int *pnum_mods,
140 : int mod_op, const char *attrib,
141 : DATA_BLOB *newvals, int num_newvals)
142 : {
143 0 : struct tldap_mod new_mod;
144 0 : struct tldap_mod *mods = *pmods;
145 0 : struct tldap_mod *mod = NULL;
146 0 : int i, num_mods;
147 :
148 0 : if (mods == NULL) {
149 0 : mods = talloc_array(mem_ctx, struct tldap_mod, 0);
150 : }
151 0 : if (mods == NULL) {
152 0 : return false;
153 : }
154 :
155 0 : num_mods = *pnum_mods;
156 :
157 0 : for (i=0; i<num_mods; i++) {
158 0 : if ((mods[i].mod_op == mod_op)
159 0 : && strequal(mods[i].attribute, attrib)) {
160 0 : mod = &mods[i];
161 0 : break;
162 : }
163 : }
164 :
165 0 : if (mod == NULL) {
166 0 : new_mod.mod_op = mod_op;
167 0 : new_mod.attribute = talloc_strdup(mods, attrib);
168 0 : if (new_mod.attribute == NULL) {
169 0 : return false;
170 : }
171 0 : new_mod.num_values = 0;
172 0 : new_mod.values = NULL;
173 0 : mod = &new_mod;
174 : }
175 :
176 0 : if ((num_newvals != 0)
177 0 : && !tldap_add_blob_vals(mods, mod, newvals, num_newvals)) {
178 0 : return false;
179 : }
180 :
181 0 : if ((i == num_mods) && (talloc_array_length(mods) < num_mods + 1)) {
182 0 : mods = talloc_realloc(talloc_tos(), mods, struct tldap_mod,
183 : num_mods+1);
184 0 : if (mods == NULL) {
185 0 : return false;
186 : }
187 0 : mods[num_mods] = *mod;
188 : }
189 :
190 0 : *pmods = mods;
191 0 : *pnum_mods += 1;
192 0 : return true;
193 : }
194 :
195 0 : bool tldap_add_mod_str(TALLOC_CTX *mem_ctx,
196 : struct tldap_mod **pmods, int *pnum_mods,
197 : int mod_op, const char *attrib, const char *str)
198 : {
199 0 : DATA_BLOB utf8;
200 0 : bool ret;
201 :
202 0 : if (!convert_string_talloc(talloc_tos(), CH_UNIX, CH_UTF8, str,
203 : strlen(str), &utf8.data, &utf8.length)) {
204 0 : return false;
205 : }
206 :
207 0 : ret = tldap_add_mod_blobs(mem_ctx, pmods, pnum_mods, mod_op, attrib,
208 : &utf8, 1);
209 0 : TALLOC_FREE(utf8.data);
210 0 : return ret;
211 : }
212 :
213 0 : static bool tldap_make_mod_blob_int(struct tldap_message *existing,
214 : TALLOC_CTX *mem_ctx,
215 : struct tldap_mod **pmods, int *pnum_mods,
216 : const char *attrib, DATA_BLOB newval,
217 : int (*comparison)(const DATA_BLOB *d1,
218 : const DATA_BLOB *d2))
219 : {
220 0 : int num_values = 0;
221 0 : DATA_BLOB *values = NULL;
222 0 : DATA_BLOB oldval = data_blob_null;
223 :
224 0 : if ((existing != NULL)
225 0 : && tldap_entry_values(existing, attrib, &values, &num_values)) {
226 :
227 0 : if (num_values > 1) {
228 : /* can't change multivalue attributes atm */
229 0 : return false;
230 : }
231 0 : if (num_values == 1) {
232 0 : oldval = values[0];
233 : }
234 : }
235 :
236 0 : if ((oldval.data != NULL) && (newval.data != NULL)
237 0 : && (comparison(&oldval, &newval) == 0)) {
238 : /* Believe it or not, but LDAP will deny a delete and
239 : an add at the same time if the values are the
240 : same... */
241 0 : DEBUG(10,("tldap_make_mod_blob_int: attribute |%s| not "
242 : "changed.\n", attrib));
243 0 : return true;
244 : }
245 :
246 0 : if (oldval.data != NULL) {
247 : /* By deleting exactly the value we found in the entry this
248 : * should be race-free in the sense that the LDAP-Server will
249 : * deny the complete operation if somebody changed the
250 : * attribute behind our back. */
251 : /* This will also allow modifying single valued attributes in
252 : * Novell NDS. In NDS you have to first remove attribute and
253 : * then you could add new value */
254 :
255 0 : DEBUG(10, ("tldap_make_mod_blob_int: deleting attribute |%s|\n",
256 : attrib));
257 0 : if (!tldap_add_mod_blobs(mem_ctx, pmods, pnum_mods,
258 : TLDAP_MOD_DELETE,
259 : attrib, &oldval, 1)) {
260 0 : return false;
261 : }
262 : }
263 :
264 : /* Regardless of the real operation (add or modify)
265 : we add the new value here. We rely on deleting
266 : the old value, should it exist. */
267 :
268 0 : if (newval.data != NULL) {
269 0 : DEBUG(10, ("tldap_make_mod_blob_int: adding attribute |%s| value len "
270 : "%d\n", attrib, (int)newval.length));
271 0 : if (!tldap_add_mod_blobs(mem_ctx, pmods, pnum_mods,
272 : TLDAP_MOD_ADD,
273 : attrib, &newval, 1)) {
274 0 : return false;
275 : }
276 : }
277 0 : return true;
278 : }
279 :
280 0 : bool tldap_make_mod_blob(struct tldap_message *existing, TALLOC_CTX *mem_ctx,
281 : struct tldap_mod **pmods, int *pnum_mods,
282 : const char *attrib, DATA_BLOB newval)
283 : {
284 0 : return tldap_make_mod_blob_int(existing, mem_ctx, pmods, pnum_mods,
285 : attrib, newval, data_blob_cmp);
286 : }
287 :
288 0 : static int compare_utf8_blobs(const DATA_BLOB *d1, const DATA_BLOB *d2)
289 : {
290 0 : char *s1, *s2;
291 0 : size_t s1len, s2len;
292 0 : int ret;
293 :
294 0 : if (!convert_string_talloc(talloc_tos(), CH_UTF8, CH_UNIX, d1->data,
295 0 : d1->length, &s1, &s1len)) {
296 : /* can't do much here */
297 0 : return 0;
298 : }
299 0 : if (!convert_string_talloc(talloc_tos(), CH_UTF8, CH_UNIX, d2->data,
300 0 : d2->length, &s2, &s2len)) {
301 : /* can't do much here */
302 0 : TALLOC_FREE(s1);
303 0 : return 0;
304 : }
305 0 : ret = strcasecmp_m(s1, s2);
306 0 : TALLOC_FREE(s2);
307 0 : TALLOC_FREE(s1);
308 0 : return ret;
309 : }
310 :
311 0 : bool tldap_make_mod_fmt(struct tldap_message *existing, TALLOC_CTX *mem_ctx,
312 : struct tldap_mod **pmods, int *pnum_mods,
313 : const char *attrib, const char *fmt, ...)
314 : {
315 0 : va_list ap;
316 0 : char *newval;
317 0 : bool ret;
318 0 : DATA_BLOB blob = data_blob_null;
319 :
320 0 : va_start(ap, fmt);
321 0 : newval = talloc_vasprintf(talloc_tos(), fmt, ap);
322 0 : va_end(ap);
323 :
324 0 : if (newval == NULL) {
325 0 : return false;
326 : }
327 :
328 0 : blob.length = strlen(newval);
329 0 : if (blob.length != 0) {
330 0 : blob.data = discard_const_p(uint8_t, newval);
331 : }
332 0 : ret = tldap_make_mod_blob_int(existing, mem_ctx, pmods, pnum_mods,
333 : attrib, blob, compare_utf8_blobs);
334 0 : TALLOC_FREE(newval);
335 0 : return ret;
336 : }
337 :
338 0 : const char *tldap_errstr(TALLOC_CTX *mem_ctx, struct tldap_context *ld,
339 : TLDAPRC rc)
340 : {
341 0 : const char *ld_error = NULL;
342 0 : char *res;
343 :
344 0 : if (ld != NULL) {
345 0 : ld_error = tldap_msg_diagnosticmessage(tldap_ctx_lastmsg(ld));
346 : }
347 0 : res = talloc_asprintf(mem_ctx, "LDAP error %d (%s), %s",
348 0 : (int)TLDAP_RC_V(rc), tldap_rc2string(rc),
349 : ld_error ? ld_error : "unknown");
350 0 : return res;
351 : }
352 :
353 0 : TLDAPRC tldap_search_va(struct tldap_context *ld, const char *base, int scope,
354 : const char *attrs[], int num_attrs, int attrsonly,
355 : TALLOC_CTX *mem_ctx, struct tldap_message ***res,
356 : const char *fmt, va_list ap)
357 : {
358 0 : char *filter;
359 0 : TLDAPRC rc;
360 :
361 0 : filter = talloc_vasprintf(talloc_tos(), fmt, ap);
362 0 : if (filter == NULL) {
363 0 : return TLDAP_NO_MEMORY;
364 : }
365 :
366 0 : rc = tldap_search(ld, base, scope, filter,
367 : attrs, num_attrs, attrsonly,
368 : NULL /*sctrls*/, 0, NULL /*cctrls*/, 0,
369 : 0 /*timelimit*/, 0 /*sizelimit*/, 0 /*deref*/,
370 : mem_ctx, res);
371 0 : TALLOC_FREE(filter);
372 0 : return rc;
373 : }
374 :
375 0 : TLDAPRC tldap_search_fmt(struct tldap_context *ld, const char *base, int scope,
376 : const char *attrs[], int num_attrs, int attrsonly,
377 : TALLOC_CTX *mem_ctx, struct tldap_message ***res,
378 : const char *fmt, ...)
379 : {
380 0 : va_list ap;
381 0 : TLDAPRC rc;
382 :
383 0 : va_start(ap, fmt);
384 0 : rc = tldap_search_va(ld, base, scope, attrs, num_attrs, attrsonly,
385 : mem_ctx, res, fmt, ap);
386 0 : va_end(ap);
387 0 : return rc;
388 : }
389 :
390 0 : bool tldap_pull_uint64(struct tldap_message *msg, const char *attr,
391 : uint64_t *presult)
392 : {
393 0 : char *str;
394 0 : uint64_t result;
395 0 : int error = 0;
396 :
397 0 : str = tldap_talloc_single_attribute(msg, attr, talloc_tos());
398 0 : if (str == NULL) {
399 0 : DEBUG(10, ("Could not find attribute %s\n", attr));
400 0 : return false;
401 : }
402 :
403 0 : result = smb_strtoull(str, NULL, 10, &error, SMB_STR_STANDARD);
404 0 : if (error != 0) {
405 0 : DBG_DEBUG("Attribute conversion failed (%s)\n",
406 : strerror(error));
407 0 : TALLOC_FREE(str);
408 0 : return false;
409 : }
410 :
411 0 : TALLOC_FREE(str);
412 0 : *presult = result;
413 0 : return true;
414 : }
415 :
416 0 : bool tldap_pull_uint32(struct tldap_message *msg, const char *attr,
417 : uint32_t *presult)
418 : {
419 0 : uint64_t result;
420 :
421 0 : if (!tldap_pull_uint64(msg, attr, &result)) {
422 0 : return false;
423 : }
424 0 : *presult = (uint32_t)result;
425 0 : return true;
426 : }
427 :
428 : struct tldap_fetch_rootdse_state {
429 : struct tldap_context *ld;
430 : struct tldap_message *rootdse;
431 : };
432 :
433 : static void tldap_fetch_rootdse_done(struct tevent_req *subreq);
434 :
435 2 : struct tevent_req *tldap_fetch_rootdse_send(TALLOC_CTX *mem_ctx,
436 : struct tevent_context *ev,
437 : struct tldap_context *ld)
438 : {
439 0 : struct tevent_req *req, *subreq;
440 0 : struct tldap_fetch_rootdse_state *state;
441 0 : static const char *attrs[2] = { "*", "+" };
442 :
443 2 : req = tevent_req_create(mem_ctx, &state,
444 : struct tldap_fetch_rootdse_state);
445 2 : if (req == NULL) {
446 0 : return NULL;
447 : }
448 2 : state->ld = ld;
449 2 : state->rootdse = NULL;
450 :
451 2 : subreq = tldap_search_send(
452 : mem_ctx, ev, ld, "", TLDAP_SCOPE_BASE, "(objectclass=*)",
453 : attrs, ARRAY_SIZE(attrs), 0, NULL, 0, NULL, 0, 0, 0, 0);
454 2 : if (tevent_req_nomem(subreq, req)) {
455 0 : return tevent_req_post(req, ev);
456 : }
457 2 : tevent_req_set_callback(subreq, tldap_fetch_rootdse_done, req);
458 2 : return req;
459 : }
460 :
461 4 : static void tldap_fetch_rootdse_done(struct tevent_req *subreq)
462 : {
463 4 : struct tevent_req *req = tevent_req_callback_data(
464 : subreq, struct tevent_req);
465 4 : struct tldap_fetch_rootdse_state *state = tevent_req_data(
466 : req, struct tldap_fetch_rootdse_state);
467 0 : struct tldap_message *msg;
468 0 : TLDAPRC rc;
469 :
470 4 : rc = tldap_search_recv(subreq, state, &msg);
471 4 : if (tevent_req_ldap_error(req, rc)) {
472 0 : return;
473 : }
474 :
475 4 : switch (tldap_msg_type(msg)) {
476 2 : case TLDAP_RES_SEARCH_ENTRY:
477 2 : if (state->rootdse != NULL) {
478 0 : goto protocol_error;
479 : }
480 2 : state->rootdse = msg;
481 2 : break;
482 2 : case TLDAP_RES_SEARCH_RESULT:
483 2 : TALLOC_FREE(subreq);
484 2 : if (state->rootdse == NULL) {
485 0 : goto protocol_error;
486 : }
487 2 : tevent_req_done(req);
488 2 : break;
489 0 : default:
490 0 : goto protocol_error;
491 : }
492 4 : return;
493 :
494 0 : protocol_error:
495 0 : tevent_req_ldap_error(req, TLDAP_PROTOCOL_ERROR);
496 0 : return;
497 : }
498 :
499 2 : TLDAPRC tldap_fetch_rootdse_recv(struct tevent_req *req)
500 : {
501 2 : struct tldap_fetch_rootdse_state *state = tevent_req_data(
502 : req, struct tldap_fetch_rootdse_state);
503 0 : TLDAPRC rc;
504 0 : char *dn;
505 :
506 2 : if (tevent_req_is_ldap_error(req, &rc)) {
507 0 : return rc;
508 : }
509 : /* Trigger parsing the dn, just to make sure it's ok */
510 2 : if (!tldap_entry_dn(state->rootdse, &dn)) {
511 0 : return TLDAP_DECODING_ERROR;
512 : }
513 2 : if (!tldap_context_setattr(state->ld, "tldap:rootdse",
514 2 : &state->rootdse)) {
515 0 : return TLDAP_NO_MEMORY;
516 : }
517 2 : return TLDAP_SUCCESS;
518 : }
519 :
520 2 : TLDAPRC tldap_fetch_rootdse(struct tldap_context *ld)
521 : {
522 2 : TALLOC_CTX *frame = talloc_stackframe();
523 0 : struct tevent_context *ev;
524 0 : struct tevent_req *req;
525 2 : TLDAPRC rc = TLDAP_NO_MEMORY;
526 :
527 2 : ev = samba_tevent_context_init(frame);
528 2 : if (ev == NULL) {
529 0 : goto fail;
530 : }
531 2 : req = tldap_fetch_rootdse_send(frame, ev, ld);
532 2 : if (req == NULL) {
533 0 : goto fail;
534 : }
535 2 : if (!tevent_req_poll(req, ev)) {
536 0 : rc = TLDAP_OPERATIONS_ERROR;
537 0 : goto fail;
538 : }
539 :
540 2 : rc = tldap_fetch_rootdse_recv(req);
541 2 : fail:
542 2 : TALLOC_FREE(frame);
543 2 : return rc;
544 : }
545 :
546 2 : struct tldap_message *tldap_rootdse(struct tldap_context *ld)
547 : {
548 2 : return talloc_get_type(tldap_context_getattr(ld, "tldap:rootdse"),
549 : struct tldap_message);
550 : }
551 :
552 0 : bool tldap_entry_has_attrvalue(struct tldap_message *msg,
553 : const char *attribute,
554 : const DATA_BLOB blob)
555 : {
556 0 : int i, num_values;
557 0 : DATA_BLOB *values;
558 :
559 0 : if (!tldap_entry_values(msg, attribute, &values, &num_values)) {
560 0 : return false;
561 : }
562 0 : for (i=0; i<num_values; i++) {
563 0 : if (data_blob_cmp(&values[i], &blob) == 0) {
564 0 : return true;
565 : }
566 : }
567 0 : return false;
568 : }
569 :
570 0 : bool tldap_supports_control(struct tldap_context *ld, const char *oid)
571 : {
572 0 : struct tldap_message *rootdse = tldap_rootdse(ld);
573 :
574 0 : if (rootdse == NULL) {
575 0 : return false;
576 : }
577 0 : return tldap_entry_has_attrvalue(rootdse, "supportedControl",
578 : data_blob_const(oid, strlen(oid)));
579 : }
580 :
581 8 : struct tldap_control *tldap_add_control(TALLOC_CTX *mem_ctx,
582 : struct tldap_control *ctrls,
583 : int num_ctrls,
584 : struct tldap_control *ctrl)
585 : {
586 0 : struct tldap_control *result;
587 :
588 8 : result = talloc_array(mem_ctx, struct tldap_control, num_ctrls+1);
589 8 : if (result == NULL) {
590 0 : return NULL;
591 : }
592 8 : if (num_ctrls > 0) {
593 0 : memcpy(result, ctrls, sizeof(struct tldap_control) * num_ctrls);
594 : }
595 8 : result[num_ctrls] = *ctrl;
596 8 : return result;
597 : }
598 :
599 : /*
600 : * Find a control returned by the server
601 : */
602 96 : struct tldap_control *tldap_msg_findcontrol(struct tldap_message *msg,
603 : const char *oid)
604 : {
605 0 : struct tldap_control *controls;
606 0 : int i, num_controls;
607 :
608 96 : tldap_msg_sctrls(msg, &num_controls, &controls);
609 :
610 96 : for (i=0; i<num_controls; i++) {
611 96 : if (strcmp(controls[i].oid, oid) == 0) {
612 96 : return &controls[i];
613 : }
614 : }
615 0 : return NULL;
616 : }
617 :
618 : struct tldap_search_paged_state {
619 : struct tevent_context *ev;
620 : struct tldap_context *ld;
621 : const char *base;
622 : const char *filter;
623 : int scope;
624 : const char **attrs;
625 : int num_attrs;
626 : int attrsonly;
627 : struct tldap_control *sctrls;
628 : int num_sctrls;
629 : struct tldap_control *cctrls;
630 : int num_cctrls;
631 : int timelimit;
632 : int sizelimit;
633 : int deref;
634 :
635 : int page_size;
636 : struct asn1_data *asn1;
637 : DATA_BLOB cookie;
638 : struct tldap_message *result;
639 : };
640 :
641 96 : static struct tevent_req *tldap_ship_paged_search(
642 : TALLOC_CTX *mem_ctx,
643 : struct tldap_search_paged_state *state)
644 : {
645 0 : struct tldap_control *pgctrl;
646 96 : struct asn1_data *asn1 = NULL;
647 :
648 96 : asn1 = asn1_init(state, ASN1_MAX_TREE_DEPTH);
649 96 : if (asn1 == NULL) {
650 0 : return NULL;
651 : }
652 96 : if (!asn1_push_tag(asn1, ASN1_SEQUENCE(0))) goto err;
653 96 : if (!asn1_write_Integer(asn1, state->page_size)) goto err;
654 96 : if (!asn1_write_OctetString(asn1, state->cookie.data, state->cookie.length)) goto err;
655 96 : if (!asn1_pop_tag(asn1)) goto err;
656 96 : state->asn1 = asn1;
657 :
658 96 : pgctrl = &state->sctrls[state->num_sctrls-1];
659 96 : pgctrl->oid = TLDAP_CONTROL_PAGEDRESULTS;
660 96 : pgctrl->critical = true;
661 96 : if (!asn1_blob(state->asn1, &pgctrl->value)) {
662 0 : goto err;
663 : }
664 96 : return tldap_search_send(mem_ctx, state->ev, state->ld, state->base,
665 : state->scope, state->filter, state->attrs,
666 : state->num_attrs, state->attrsonly,
667 : state->sctrls, state->num_sctrls,
668 : state->cctrls, state->num_cctrls,
669 : state->timelimit, state->sizelimit,
670 : state->deref);
671 :
672 0 : err:
673 :
674 0 : TALLOC_FREE(asn1);
675 0 : return NULL;
676 : }
677 :
678 : static void tldap_search_paged_done(struct tevent_req *subreq);
679 :
680 2 : struct tevent_req *tldap_search_paged_send(TALLOC_CTX *mem_ctx,
681 : struct tevent_context *ev,
682 : struct tldap_context *ld,
683 : const char *base, int scope,
684 : const char *filter,
685 : const char **attrs,
686 : int num_attrs,
687 : int attrsonly,
688 : struct tldap_control *sctrls,
689 : int num_sctrls,
690 : struct tldap_control *cctrls,
691 : int num_cctrls,
692 : int timelimit,
693 : int sizelimit,
694 : int deref,
695 : int page_size)
696 : {
697 0 : struct tevent_req *req, *subreq;
698 0 : struct tldap_search_paged_state *state;
699 0 : struct tldap_control empty_control;
700 :
701 2 : req = tevent_req_create(mem_ctx, &state,
702 : struct tldap_search_paged_state);
703 2 : if (req == NULL) {
704 0 : return NULL;
705 : }
706 2 : state->ev = ev;
707 2 : state->ld = ld;
708 2 : state->base = base;
709 2 : state->filter = filter;
710 2 : state->scope = scope;
711 2 : state->attrs = attrs;
712 2 : state->num_attrs = num_attrs;
713 2 : state->attrsonly = attrsonly;
714 2 : state->cctrls = cctrls;
715 2 : state->num_cctrls = num_cctrls;
716 2 : state->timelimit = timelimit;
717 2 : state->sizelimit = sizelimit;
718 2 : state->deref = deref;
719 :
720 2 : state->page_size = page_size;
721 2 : state->asn1 = NULL;
722 2 : state->cookie = data_blob_null;
723 :
724 2 : ZERO_STRUCT(empty_control);
725 :
726 2 : state->sctrls = tldap_add_control(state, sctrls, num_sctrls,
727 : &empty_control);
728 2 : if (tevent_req_nomem(state->sctrls, req)) {
729 0 : return tevent_req_post(req, ev);
730 : }
731 2 : state->num_sctrls = num_sctrls+1;
732 :
733 2 : subreq = tldap_ship_paged_search(state, state);
734 2 : if (tevent_req_nomem(subreq, req)) {
735 0 : return tevent_req_post(req, ev);
736 : }
737 2 : tevent_req_set_callback(subreq, tldap_search_paged_done, req);
738 :
739 2 : return req;
740 : }
741 :
742 572 : static void tldap_search_paged_done(struct tevent_req *subreq)
743 : {
744 572 : struct tevent_req *req = tevent_req_callback_data(
745 : subreq, struct tevent_req);
746 572 : struct tldap_search_paged_state *state = tevent_req_data(
747 : req, struct tldap_search_paged_state);
748 572 : struct asn1_data *asn1 = NULL;
749 0 : struct tldap_control *pgctrl;
750 0 : TLDAPRC rc;
751 0 : int size;
752 :
753 572 : rc = tldap_search_recv(subreq, state, &state->result);
754 572 : if (tevent_req_ldap_error(req, rc)) {
755 572 : return;
756 : }
757 :
758 572 : TALLOC_FREE(state->asn1);
759 :
760 572 : switch (tldap_msg_type(state->result)) {
761 476 : case TLDAP_RES_SEARCH_ENTRY:
762 : case TLDAP_RES_SEARCH_REFERENCE:
763 476 : tevent_req_notify_callback(req);
764 476 : return;
765 96 : case TLDAP_RES_SEARCH_RESULT:
766 96 : break;
767 0 : default:
768 0 : TALLOC_FREE(subreq);
769 0 : tevent_req_ldap_error(req, TLDAP_PROTOCOL_ERROR);
770 0 : return;
771 : }
772 :
773 96 : TALLOC_FREE(subreq);
774 :
775 : /* We've finished one paged search, fire the next */
776 :
777 96 : pgctrl = tldap_msg_findcontrol(state->result,
778 : TLDAP_CONTROL_PAGEDRESULTS);
779 96 : if (pgctrl == NULL) {
780 : /* RFC2696 requires the server to return the control */
781 0 : tevent_req_ldap_error(req, TLDAP_PROTOCOL_ERROR);
782 0 : return;
783 : }
784 :
785 96 : TALLOC_FREE(state->cookie.data);
786 :
787 96 : asn1 = asn1_init(talloc_tos(), ASN1_MAX_TREE_DEPTH);
788 96 : if (tevent_req_nomem(asn1, req)) {
789 0 : return;
790 : }
791 :
792 96 : asn1_load_nocopy(asn1, pgctrl->value.data, pgctrl->value.length);
793 96 : if (!asn1_start_tag(asn1, ASN1_SEQUENCE(0))) goto err;
794 96 : if (!asn1_read_Integer(asn1, &size)) goto err;
795 96 : if (!asn1_read_OctetString(asn1, state, &state->cookie)) goto err;
796 96 : if (!asn1_end_tag(asn1)) goto err;
797 :
798 96 : TALLOC_FREE(asn1);
799 :
800 96 : if (state->cookie.length == 0) {
801 : /* We're done, no cookie anymore */
802 2 : tevent_req_done(req);
803 2 : return;
804 : }
805 :
806 94 : TALLOC_FREE(state->result);
807 :
808 94 : subreq = tldap_ship_paged_search(state, state);
809 94 : if (tevent_req_nomem(subreq, req)) {
810 0 : return;
811 : }
812 94 : tevent_req_set_callback(subreq, tldap_search_paged_done, req);
813 :
814 94 : return;
815 0 : err:
816 :
817 0 : TALLOC_FREE(asn1);
818 0 : tevent_req_ldap_error(req, TLDAP_DECODING_ERROR);
819 : }
820 :
821 478 : TLDAPRC tldap_search_paged_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
822 : struct tldap_message **pmsg)
823 : {
824 478 : struct tldap_search_paged_state *state = tevent_req_data(
825 : req, struct tldap_search_paged_state);
826 0 : TLDAPRC rc;
827 :
828 478 : if (!tevent_req_is_in_progress(req)
829 2 : && tevent_req_is_ldap_error(req, &rc)) {
830 0 : return rc;
831 : }
832 478 : if (tevent_req_is_in_progress(req)) {
833 476 : switch (tldap_msg_type(state->result)) {
834 476 : case TLDAP_RES_SEARCH_ENTRY:
835 : case TLDAP_RES_SEARCH_REFERENCE:
836 476 : break;
837 0 : default:
838 0 : return TLDAP_PROTOCOL_ERROR;
839 : }
840 : }
841 478 : *pmsg = talloc_move(mem_ctx, &state->result);
842 478 : return TLDAP_SUCCESS;
843 : }
|