/src/samba/lib/ldb/common/ldb_controls.c
Line | Count | Source |
1 | | /* |
2 | | ldb database library |
3 | | |
4 | | Copyright (C) Simo Sorce 2005 |
5 | | |
6 | | ** NOTE! The following LGPL license applies to the ldb |
7 | | ** library. This does NOT imply that all of Samba is released |
8 | | ** under the LGPL |
9 | | |
10 | | This library is free software; you can redistribute it and/or |
11 | | modify it under the terms of the GNU Lesser General Public |
12 | | License as published by the Free Software Foundation; either |
13 | | version 3 of the License, or (at your option) any later version. |
14 | | |
15 | | This library is distributed in the hope that it will be useful, |
16 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
18 | | Lesser General Public License for more details. |
19 | | |
20 | | You should have received a copy of the GNU Lesser General Public |
21 | | License along with this library; if not, see <http://www.gnu.org/licenses/>. |
22 | | */ |
23 | | |
24 | | /* |
25 | | * Name: ldb_controls.c |
26 | | * |
27 | | * Component: ldb controls utility functions |
28 | | * |
29 | | * Description: helper functions for control modules |
30 | | * |
31 | | * Author: Simo Sorce |
32 | | */ |
33 | | |
34 | | #include "ldb_private.h" |
35 | | |
36 | | /* check if a control with the specified "oid" exist and return it */ |
37 | | /* returns NULL if not found */ |
38 | | struct ldb_control *ldb_controls_get_control(struct ldb_control **controls, const char *oid) |
39 | 0 | { |
40 | 0 | unsigned int i; |
41 | |
|
42 | 0 | if (controls != NULL) { |
43 | 0 | for (i = 0; controls[i]; i++) { |
44 | 0 | if (controls[i]->oid && strcmp(oid, controls[i]->oid) == 0) { |
45 | 0 | break; |
46 | 0 | } |
47 | 0 | } |
48 | |
|
49 | 0 | return controls[i]; |
50 | 0 | } |
51 | | |
52 | 0 | return NULL; |
53 | 0 | } |
54 | | |
55 | | /* check if a control with the specified "oid" exist and return it */ |
56 | | /* returns NULL if not found */ |
57 | | struct ldb_control *ldb_request_get_control(struct ldb_request *req, const char *oid) |
58 | 0 | { |
59 | 0 | return ldb_controls_get_control(req->controls, oid); |
60 | 0 | } |
61 | | |
62 | | /* check if a control with the specified "oid" exist and return it */ |
63 | | /* returns NULL if not found */ |
64 | | struct ldb_control *ldb_reply_get_control(struct ldb_reply *rep, const char *oid) |
65 | 0 | { |
66 | 0 | return ldb_controls_get_control(rep->controls, oid); |
67 | 0 | } |
68 | | |
69 | | /* |
70 | | * Saves the current controls list into the "saver" (can also be NULL) and |
71 | | * replace the one in "req" with a new one excluding the "exclude" control |
72 | | * (if it is NULL then the list remains the same) |
73 | | * |
74 | | * Returns 0 on error. |
75 | | */ |
76 | | int ldb_save_controls(struct ldb_control *exclude, struct ldb_request *req, struct ldb_control ***saver) |
77 | 0 | { |
78 | 0 | struct ldb_control **lcs, **lcs_old; |
79 | 0 | unsigned int i, j; |
80 | |
|
81 | 0 | lcs_old = req->controls; |
82 | 0 | if (saver != NULL) { |
83 | 0 | *saver = lcs_old; |
84 | 0 | } |
85 | |
|
86 | 0 | for (i = 0; req->controls && req->controls[i]; i++); |
87 | 0 | if (i == 0) { |
88 | 0 | req->controls = NULL; |
89 | 0 | return 1; |
90 | 0 | } |
91 | | |
92 | 0 | lcs = talloc_array(req, struct ldb_control *, i + 1); |
93 | 0 | if (!lcs) { |
94 | 0 | return 0; |
95 | 0 | } |
96 | | |
97 | 0 | for (i = 0, j = 0; lcs_old[i]; i++) { |
98 | 0 | if (exclude == lcs_old[i]) continue; |
99 | 0 | lcs[j] = lcs_old[i]; |
100 | 0 | j++; |
101 | 0 | } |
102 | 0 | lcs[j] = NULL; |
103 | |
|
104 | 0 | req->controls = talloc_realloc(req, lcs, struct ldb_control *, j + 1); |
105 | 0 | if (req->controls == NULL) { |
106 | 0 | return 0; |
107 | 0 | } |
108 | 0 | return 1; |
109 | 0 | } |
110 | | |
111 | | /* |
112 | | * Returns a list of controls, except the one specified with "exclude" (can |
113 | | * also be NULL). Included controls become a child of returned list if they |
114 | | * were children of "controls_in". |
115 | | * |
116 | | * Returns NULL on error (OOM) or an empty control list. |
117 | | */ |
118 | | struct ldb_control **ldb_controls_except_specified(struct ldb_control **controls_in, |
119 | | TALLOC_CTX *mem_ctx, |
120 | | struct ldb_control *exclude) |
121 | 0 | { |
122 | 0 | struct ldb_control **lcs = NULL; |
123 | 0 | unsigned int i, j, n; |
124 | |
|
125 | 0 | for (i = 0; controls_in && controls_in[i]; i++); |
126 | 0 | if (i == 0) { |
127 | 0 | return NULL; |
128 | 0 | } |
129 | 0 | n = i; |
130 | |
|
131 | 0 | for (i = 0, j = 0; controls_in && controls_in[i]; i++) { |
132 | 0 | if (exclude == controls_in[i]) continue; |
133 | | |
134 | 0 | if (!lcs) { |
135 | | /* Allocate here so if we remove the only |
136 | | * control, or there were no controls, we |
137 | | * don't allocate at all, and just return |
138 | | * NULL */ |
139 | 0 | lcs = talloc_array(mem_ctx, struct ldb_control *, |
140 | 0 | n + 1); |
141 | 0 | if (!lcs) { |
142 | 0 | return NULL; |
143 | 0 | } |
144 | 0 | } |
145 | | |
146 | 0 | lcs[j] = controls_in[i]; |
147 | 0 | talloc_reparent(controls_in, lcs, lcs[j]); |
148 | 0 | j++; |
149 | 0 | } |
150 | 0 | if (lcs) { |
151 | 0 | lcs[j] = NULL; |
152 | |
|
153 | 0 | lcs = talloc_realloc(mem_ctx, lcs, struct ldb_control *, j + 1); |
154 | 0 | } |
155 | |
|
156 | 0 | return lcs; |
157 | 0 | } |
158 | | |
159 | | /* check if there's any control marked as critical in the list */ |
160 | | /* return True if any, False if none */ |
161 | | int ldb_check_critical_controls(struct ldb_control **controls) |
162 | 0 | { |
163 | 0 | unsigned int i; |
164 | |
|
165 | 0 | if (controls == NULL) { |
166 | 0 | return 0; |
167 | 0 | } |
168 | | |
169 | 0 | for (i = 0; controls[i]; i++) { |
170 | 0 | if (controls[i]->critical) { |
171 | 0 | return 1; |
172 | 0 | } |
173 | 0 | } |
174 | | |
175 | 0 | return 0; |
176 | 0 | } |
177 | | |
178 | | int ldb_request_add_control(struct ldb_request *req, const char *oid, bool critical, void *data) |
179 | 0 | { |
180 | 0 | unsigned int i, n; |
181 | 0 | struct ldb_control **ctrls; |
182 | 0 | struct ldb_control *ctrl; |
183 | |
|
184 | 0 | for (n=0; req->controls && req->controls[n];n++) { |
185 | | /* having two controls of the same OID makes no sense */ |
186 | 0 | if (req->controls[n]->oid && strcmp(oid, req->controls[n]->oid) == 0) { |
187 | 0 | return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS; |
188 | 0 | } |
189 | 0 | } |
190 | | |
191 | 0 | ctrls = talloc_array(req, |
192 | 0 | struct ldb_control *, |
193 | 0 | n + 2); |
194 | 0 | if (!ctrls) return LDB_ERR_OPERATIONS_ERROR; |
195 | | |
196 | 0 | for (i=0; i<n; i++) { |
197 | 0 | ctrls[i] = req->controls[i]; |
198 | 0 | } |
199 | |
|
200 | 0 | req->controls = ctrls; |
201 | 0 | ctrls[n] = NULL; |
202 | 0 | ctrls[n+1] = NULL; |
203 | |
|
204 | 0 | ctrl = talloc(ctrls, struct ldb_control); |
205 | 0 | if (!ctrl) return LDB_ERR_OPERATIONS_ERROR; |
206 | | |
207 | 0 | ctrl->oid = talloc_strdup(ctrl, oid); |
208 | 0 | if (!ctrl->oid) return LDB_ERR_OPERATIONS_ERROR; |
209 | 0 | ctrl->critical = critical; |
210 | 0 | ctrl->data = data; |
211 | |
|
212 | 0 | ctrls[n] = ctrl; |
213 | 0 | return LDB_SUCCESS; |
214 | 0 | } |
215 | | |
216 | | int ldb_reply_add_control(struct ldb_reply *ares, const char *oid, bool critical, void *data) |
217 | 0 | { |
218 | 0 | unsigned n; |
219 | 0 | struct ldb_control **ctrls; |
220 | 0 | struct ldb_control *ctrl; |
221 | |
|
222 | 0 | for (n=0; ares->controls && ares->controls[n];) { |
223 | | /* having two controls of the same OID makes no sense */ |
224 | 0 | if (ares->controls[n]->oid && strcmp(oid, ares->controls[n]->oid) == 0) { |
225 | 0 | return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS; |
226 | 0 | } |
227 | 0 | n++; |
228 | 0 | } |
229 | | |
230 | 0 | ctrls = talloc_realloc(ares, ares->controls, |
231 | 0 | struct ldb_control *, |
232 | 0 | n + 2); |
233 | 0 | if (!ctrls) return LDB_ERR_OPERATIONS_ERROR; |
234 | 0 | ares->controls = ctrls; |
235 | 0 | ctrls[n] = NULL; |
236 | 0 | ctrls[n+1] = NULL; |
237 | |
|
238 | 0 | ctrl = talloc(ctrls, struct ldb_control); |
239 | 0 | if (!ctrl) return LDB_ERR_OPERATIONS_ERROR; |
240 | | |
241 | 0 | ctrl->oid = talloc_strdup(ctrl, oid); |
242 | 0 | if (!ctrl->oid) return LDB_ERR_OPERATIONS_ERROR; |
243 | 0 | ctrl->critical = critical; |
244 | 0 | ctrl->data = data; |
245 | |
|
246 | 0 | ctrls[n] = ctrl; |
247 | 0 | return LDB_SUCCESS; |
248 | 0 | } |
249 | | |
250 | | /* Add a control to the request, replacing the old one if it is already in the request */ |
251 | | int ldb_request_replace_control(struct ldb_request *req, const char *oid, bool critical, void *data) |
252 | 0 | { |
253 | 0 | unsigned int n; |
254 | 0 | int ret; |
255 | |
|
256 | 0 | ret = ldb_request_add_control(req, oid, critical, data); |
257 | 0 | if (ret != LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS) { |
258 | 0 | return ret; |
259 | 0 | } |
260 | | |
261 | 0 | for (n=0; req->controls[n];n++) { |
262 | 0 | if (req->controls[n]->oid && strcmp(oid, req->controls[n]->oid) == 0) { |
263 | 0 | req->controls[n]->critical = critical; |
264 | 0 | req->controls[n]->data = data; |
265 | 0 | return LDB_SUCCESS; |
266 | 0 | } |
267 | 0 | } |
268 | | |
269 | 0 | return LDB_ERR_OPERATIONS_ERROR; |
270 | 0 | } |
271 | | |
272 | | /* |
273 | | * Return a control as string |
274 | | * the project (ie. name:value1:value2:...:valuen |
275 | | * The string didn't include the criticity of the critical flag |
276 | | */ |
277 | | char *ldb_control_to_string(TALLOC_CTX *mem_ctx, const struct ldb_control *control) |
278 | 0 | { |
279 | 0 | char *res = NULL; |
280 | |
|
281 | 0 | if (strcmp(control->oid, LDB_CONTROL_PAGED_RESULTS_OID) == 0) { |
282 | 0 | struct ldb_paged_control *rep_control = talloc_get_type(control->data, struct ldb_paged_control); |
283 | 0 | char *cookie; |
284 | 0 | if (rep_control == NULL) { |
285 | 0 | return NULL; |
286 | 0 | } |
287 | | |
288 | 0 | cookie = ldb_base64_encode(mem_ctx, rep_control->cookie, rep_control->cookie_len); |
289 | 0 | if (cookie == NULL) { |
290 | 0 | return NULL; |
291 | 0 | } |
292 | 0 | if (cookie[0] != '\0') { |
293 | 0 | res = talloc_asprintf(mem_ctx, "%s:%d:%s", |
294 | 0 | LDB_CONTROL_PAGED_RESULTS_NAME, |
295 | 0 | control->critical, |
296 | 0 | cookie); |
297 | |
|
298 | 0 | talloc_free(cookie); |
299 | 0 | } else { |
300 | 0 | res = talloc_asprintf(mem_ctx, "%s:%d", |
301 | 0 | LDB_CONTROL_PAGED_RESULTS_NAME, |
302 | 0 | control->critical); |
303 | 0 | } |
304 | 0 | return res; |
305 | 0 | } |
306 | | |
307 | 0 | if (strcmp(control->oid, LDB_CONTROL_VLV_RESP_OID) == 0) { |
308 | 0 | struct ldb_vlv_resp_control *rep_control = talloc_get_type(control->data, |
309 | 0 | struct ldb_vlv_resp_control); |
310 | |
|
311 | 0 | char *cookie; |
312 | |
|
313 | 0 | if (rep_control == NULL) { |
314 | 0 | return NULL; |
315 | 0 | } |
316 | | |
317 | 0 | cookie = ldb_base64_encode(mem_ctx, |
318 | 0 | (char *)rep_control->contextId, |
319 | 0 | rep_control->ctxid_len); |
320 | 0 | if (cookie == NULL) { |
321 | 0 | return NULL; |
322 | 0 | } |
323 | | |
324 | 0 | res = talloc_asprintf(mem_ctx, "%s:%d:%d:%d:%d:%s", |
325 | 0 | LDB_CONTROL_VLV_RESP_NAME, |
326 | 0 | control->critical, |
327 | 0 | rep_control->targetPosition, |
328 | 0 | rep_control->contentCount, |
329 | 0 | rep_control->vlv_result, |
330 | 0 | cookie); |
331 | |
|
332 | 0 | return res; |
333 | 0 | } |
334 | | |
335 | 0 | if (strcmp(control->oid, LDB_CONTROL_SORT_RESP_OID) == 0) { |
336 | 0 | struct ldb_sort_resp_control *rep_control = talloc_get_type(control->data, |
337 | 0 | struct ldb_sort_resp_control); |
338 | |
|
339 | 0 | if (rep_control == NULL) { |
340 | 0 | return NULL; |
341 | 0 | } |
342 | 0 | res = talloc_asprintf(mem_ctx, "%s:%d:%d:%s", |
343 | 0 | LDB_CONTROL_SORT_RESP_NAME, |
344 | 0 | control->critical, |
345 | 0 | rep_control->result, |
346 | 0 | rep_control->attr_desc); |
347 | |
|
348 | 0 | return res; |
349 | 0 | } |
350 | | |
351 | 0 | if (strcmp(control->oid, LDB_CONTROL_ASQ_OID) == 0) { |
352 | 0 | struct ldb_asq_control *rep_control = talloc_get_type(control->data, |
353 | 0 | struct ldb_asq_control); |
354 | |
|
355 | 0 | if (rep_control == NULL) { |
356 | 0 | return NULL; |
357 | 0 | } |
358 | 0 | res = talloc_asprintf(mem_ctx, "%s:%d:%d", |
359 | 0 | LDB_CONTROL_ASQ_NAME, |
360 | 0 | control->critical, |
361 | 0 | rep_control->result); |
362 | |
|
363 | 0 | return res; |
364 | 0 | } |
365 | | |
366 | 0 | if (strcmp(control->oid, LDB_CONTROL_DIRSYNC_OID) == 0) { |
367 | 0 | char *cookie; |
368 | 0 | struct ldb_dirsync_control *rep_control = talloc_get_type(control->data, |
369 | 0 | struct ldb_dirsync_control); |
370 | |
|
371 | 0 | if (rep_control == NULL) { |
372 | 0 | return NULL; |
373 | 0 | } |
374 | 0 | cookie = ldb_base64_encode(mem_ctx, rep_control->cookie, |
375 | 0 | rep_control->cookie_len); |
376 | 0 | if (cookie == NULL) { |
377 | 0 | return NULL; |
378 | 0 | } |
379 | 0 | res = talloc_asprintf(mem_ctx, "%s:%d:%d:%d:%s", |
380 | 0 | LDB_CONTROL_DIRSYNC_NAME, |
381 | 0 | control->critical, |
382 | 0 | rep_control->flags, |
383 | 0 | rep_control->max_attributes, |
384 | 0 | cookie); |
385 | |
|
386 | 0 | talloc_free(cookie); |
387 | 0 | return res; |
388 | 0 | } |
389 | 0 | if (strcmp(control->oid, LDB_CONTROL_DIRSYNC_EX_OID) == 0) { |
390 | 0 | char *cookie; |
391 | 0 | struct ldb_dirsync_control *rep_control = talloc_get_type(control->data, |
392 | 0 | struct ldb_dirsync_control); |
393 | |
|
394 | 0 | if (rep_control == NULL) { |
395 | 0 | return NULL; |
396 | 0 | } |
397 | 0 | cookie = ldb_base64_encode(mem_ctx, rep_control->cookie, |
398 | 0 | rep_control->cookie_len); |
399 | 0 | if (cookie == NULL) { |
400 | 0 | return NULL; |
401 | 0 | } |
402 | 0 | res = talloc_asprintf(mem_ctx, "%s:%d:%d:%d:%s", |
403 | 0 | LDB_CONTROL_DIRSYNC_EX_NAME, |
404 | 0 | control->critical, |
405 | 0 | rep_control->flags, |
406 | 0 | rep_control->max_attributes, |
407 | 0 | cookie); |
408 | |
|
409 | 0 | talloc_free(cookie); |
410 | 0 | return res; |
411 | 0 | } |
412 | | |
413 | 0 | if (strcmp(control->oid, LDB_CONTROL_VERIFY_NAME_OID) == 0) { |
414 | 0 | struct ldb_verify_name_control *rep_control = talloc_get_type(control->data, struct ldb_verify_name_control); |
415 | |
|
416 | 0 | if (rep_control == NULL) { |
417 | 0 | return NULL; |
418 | 0 | } |
419 | 0 | if (rep_control->gc != NULL) { |
420 | 0 | res = talloc_asprintf(mem_ctx, "%s:%d:%d:%s", |
421 | 0 | LDB_CONTROL_VERIFY_NAME_NAME, |
422 | 0 | control->critical, |
423 | 0 | rep_control->flags, |
424 | 0 | rep_control->gc); |
425 | |
|
426 | 0 | } else { |
427 | 0 | res = talloc_asprintf(mem_ctx, "%s:%d:%d", |
428 | 0 | LDB_CONTROL_VERIFY_NAME_NAME, |
429 | 0 | control->critical, |
430 | 0 | rep_control->flags); |
431 | 0 | } |
432 | 0 | return res; |
433 | 0 | } |
434 | | |
435 | | /* |
436 | | * From here we don't know the control |
437 | | */ |
438 | 0 | if (control->data == NULL) { |
439 | | /* |
440 | | * We don't know the control but there is no real data attached |
441 | | * to it so we can represent it with local_oid:oid:criticity. |
442 | | */ |
443 | 0 | res = talloc_asprintf(mem_ctx, "local_oid:%s:%d", |
444 | 0 | control->oid, |
445 | 0 | control->critical); |
446 | 0 | } else { |
447 | 0 | res = talloc_asprintf(mem_ctx, "unknown oid:%s", |
448 | 0 | control->oid); |
449 | 0 | } |
450 | 0 | return res; |
451 | 0 | } |
452 | | |
453 | | |
454 | | /* |
455 | | * A little trick to allow one to use constants defined in headers rather than |
456 | | * hardwritten in the file. |
457 | | * "sizeof" will return the \0 char as well so it will take the place of ":" |
458 | | * in the length of the string. |
459 | | */ |
460 | 0 | #define LDB_CONTROL_CMP(control, NAME) strncmp(control, NAME ":", sizeof(NAME)) |
461 | | |
462 | | /* Parse one string and return associated control if parsing is successful*/ |
463 | | struct ldb_control *ldb_parse_control_from_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *control_strings) |
464 | 0 | { |
465 | 0 | struct ldb_control *ctrl; |
466 | |
|
467 | 0 | if (!(ctrl = talloc(mem_ctx, struct ldb_control))) { |
468 | 0 | ldb_oom(ldb); |
469 | 0 | return NULL; |
470 | 0 | } |
471 | | |
472 | 0 | if (LDB_CONTROL_CMP(control_strings, |
473 | 0 | LDB_CONTROL_VLV_REQ_NAME) == 0) { |
474 | 0 | struct ldb_vlv_req_control *control; |
475 | 0 | const char *p; |
476 | 0 | char attr[1024]; |
477 | 0 | char ctxid[1024]; |
478 | 0 | int crit, bc, ac, os, cc, ret; |
479 | |
|
480 | 0 | attr[0] = '\0'; |
481 | 0 | ctxid[0] = '\0'; |
482 | 0 | p = &(control_strings[sizeof(LDB_CONTROL_VLV_REQ_NAME)]); |
483 | 0 | ret = sscanf(p, "%d:%d:%d:%d:%d:%1023[^$]", &crit, &bc, &ac, &os, &cc, ctxid); |
484 | | /* We allow 2 ways to encode the GT_EQ case, because the |
485 | | comparison string might contain null bytes or colons, which |
486 | | would break sscanf (or indeed any parsing mechanism). */ |
487 | 0 | if (ret == 3) { |
488 | 0 | ret = sscanf(p, "%d:%d:%d:>=%1023[^:]:%1023[^$]", &crit, &bc, &ac, attr, ctxid); |
489 | 0 | } |
490 | 0 | if (ret == 3) { |
491 | 0 | int len; |
492 | 0 | ret = sscanf(p, "%d:%d:%d:base64>=%1023[^:]:%1023[^$]", &crit, &bc, &ac, attr, ctxid); |
493 | 0 | len = ldb_base64_decode(attr); |
494 | 0 | if (len < 0) { |
495 | 0 | ret = -1; |
496 | 0 | } |
497 | 0 | } |
498 | |
|
499 | 0 | if ((ret < 4) || (crit < 0) || (crit > 1)) { |
500 | 0 | ldb_set_errstring(ldb, |
501 | 0 | "invalid VLV control syntax\n" |
502 | 0 | " syntax: crit(b):bc(n):ac(n):" |
503 | 0 | "{os(n):cc(n)|>=val(s)|base64>=val(o)}[:ctxid(o)]\n" |
504 | 0 | " note: b = boolean, n = number, s = string, o = b64 binary blob"); |
505 | 0 | talloc_free(ctrl); |
506 | 0 | return NULL; |
507 | 0 | } |
508 | 0 | ctrl->oid = LDB_CONTROL_VLV_REQ_OID; |
509 | 0 | ctrl->critical = crit; |
510 | 0 | if (!(control = talloc(ctrl, |
511 | 0 | struct ldb_vlv_req_control))) { |
512 | 0 | ldb_oom(ldb); |
513 | 0 | talloc_free(ctrl); |
514 | 0 | return NULL; |
515 | 0 | } |
516 | 0 | control->beforeCount = bc; |
517 | 0 | control->afterCount = ac; |
518 | 0 | if (attr[0]) { |
519 | 0 | control->type = 1; |
520 | 0 | control->match.gtOrEq.value = talloc_strdup(control, attr); |
521 | 0 | control->match.gtOrEq.value_len = strlen(attr); |
522 | 0 | } else { |
523 | 0 | control->type = 0; |
524 | 0 | control->match.byOffset.offset = os; |
525 | 0 | control->match.byOffset.contentCount = cc; |
526 | 0 | } |
527 | 0 | if (ctxid[0]) { |
528 | 0 | int len = ldb_base64_decode(ctxid); |
529 | 0 | if (len < 0) { |
530 | 0 | ldb_set_errstring(ldb, |
531 | 0 | "invalid VLV context_id\n"); |
532 | 0 | talloc_free(ctrl); |
533 | 0 | return NULL; |
534 | 0 | } |
535 | 0 | control->ctxid_len = len; |
536 | 0 | control->contextId = talloc_memdup(control, ctxid, |
537 | 0 | control->ctxid_len); |
538 | 0 | if (control->contextId == NULL) { |
539 | 0 | ldb_oom(ldb); |
540 | 0 | talloc_free(ctrl); |
541 | 0 | return NULL; |
542 | 0 | } |
543 | 0 | } else { |
544 | 0 | control->ctxid_len = 0; |
545 | 0 | control->contextId = NULL; |
546 | 0 | } |
547 | 0 | ctrl->data = control; |
548 | |
|
549 | 0 | return ctrl; |
550 | 0 | } |
551 | | |
552 | 0 | if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_DIRSYNC_NAME) == 0) { |
553 | 0 | struct ldb_dirsync_control *control; |
554 | 0 | const char *p; |
555 | 0 | char *cookie = NULL; |
556 | 0 | int crit, max_attrs, ret; |
557 | 0 | uint32_t flags; |
558 | |
|
559 | 0 | cookie = talloc_zero_array(ctrl, char, |
560 | 0 | strlen(control_strings) + 1); |
561 | 0 | if (cookie == NULL) { |
562 | 0 | ldb_oom(ldb); |
563 | 0 | talloc_free(ctrl); |
564 | 0 | return NULL; |
565 | 0 | } |
566 | | |
567 | 0 | p = &(control_strings[sizeof(LDB_CONTROL_DIRSYNC_NAME)]); |
568 | 0 | ret = sscanf(p, "%d:%u:%d:%[^$]", &crit, &flags, &max_attrs, cookie); |
569 | |
|
570 | 0 | if ((ret < 3) || (crit < 0) || (crit > 1) || (max_attrs < 0)) { |
571 | 0 | ldb_set_errstring(ldb, |
572 | 0 | "invalid dirsync control syntax\n" |
573 | 0 | " syntax: crit(b):flags(n):max_attrs(n)[:cookie(o)]\n" |
574 | 0 | " note: b = boolean, n = number, o = b64 binary blob"); |
575 | 0 | talloc_free(ctrl); |
576 | 0 | return NULL; |
577 | 0 | } |
578 | | |
579 | | /* w2k3 seems to ignore the parameter, |
580 | | * but w2k sends a wrong cookie when this value is to small |
581 | | * this would cause looping forever, while getting |
582 | | * the same data and same cookie forever |
583 | | */ |
584 | 0 | if (max_attrs == 0) max_attrs = 0x0FFFFFFF; |
585 | |
|
586 | 0 | ctrl->oid = LDB_CONTROL_DIRSYNC_OID; |
587 | 0 | ctrl->critical = crit; |
588 | 0 | control = talloc(ctrl, struct ldb_dirsync_control); |
589 | 0 | if (control == NULL) { |
590 | 0 | ldb_oom(ldb); |
591 | 0 | talloc_free(ctrl); |
592 | 0 | return NULL; |
593 | 0 | } |
594 | 0 | control->flags = flags; |
595 | 0 | control->max_attributes = max_attrs; |
596 | 0 | if (*cookie) { |
597 | 0 | int len = ldb_base64_decode(cookie); |
598 | 0 | if (len < 0) { |
599 | 0 | ldb_set_errstring(ldb, |
600 | 0 | "invalid dirsync cookie\n"); |
601 | 0 | talloc_free(ctrl); |
602 | 0 | return NULL; |
603 | 0 | } |
604 | 0 | control->cookie_len = len; |
605 | 0 | control->cookie = (char *)talloc_memdup(control, cookie, control->cookie_len); |
606 | 0 | if (control->cookie == NULL) { |
607 | 0 | ldb_oom(ldb); |
608 | 0 | talloc_free(ctrl); |
609 | 0 | return NULL; |
610 | 0 | } |
611 | 0 | } else { |
612 | 0 | control->cookie = NULL; |
613 | 0 | control->cookie_len = 0; |
614 | 0 | } |
615 | 0 | ctrl->data = control; |
616 | 0 | TALLOC_FREE(cookie); |
617 | |
|
618 | 0 | return ctrl; |
619 | 0 | } |
620 | 0 | if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_DIRSYNC_EX_NAME) == 0) { |
621 | 0 | struct ldb_dirsync_control *control; |
622 | 0 | const char *p; |
623 | 0 | char *cookie = NULL; |
624 | 0 | int crit, max_attrs, ret; |
625 | 0 | uint32_t flags; |
626 | |
|
627 | 0 | cookie = talloc_zero_array(ctrl, char, |
628 | 0 | strlen(control_strings) + 1); |
629 | 0 | if (cookie == NULL) { |
630 | 0 | ldb_oom(ldb); |
631 | 0 | talloc_free(ctrl); |
632 | 0 | return NULL; |
633 | 0 | } |
634 | | |
635 | 0 | p = &(control_strings[sizeof(LDB_CONTROL_DIRSYNC_EX_NAME)]); |
636 | 0 | ret = sscanf(p, "%d:%u:%d:%1023[^$]", &crit, &flags, &max_attrs, cookie); |
637 | |
|
638 | 0 | if ((ret < 3) || (crit < 0) || (crit > 1) || (max_attrs < 0)) { |
639 | 0 | ldb_set_errstring(ldb, |
640 | 0 | "invalid dirsync_ex control syntax\n" |
641 | 0 | " syntax: crit(b):flags(n):max_attrs(n)[:cookie(o)]\n" |
642 | 0 | " note: b = boolean, n = number, o = b64 binary blob"); |
643 | 0 | talloc_free(ctrl); |
644 | 0 | return NULL; |
645 | 0 | } |
646 | | |
647 | | /* w2k3 seems to ignore the parameter, |
648 | | * but w2k sends a wrong cookie when this value is to small |
649 | | * this would cause looping forever, while getting |
650 | | * the same data and same cookie forever |
651 | | */ |
652 | 0 | if (max_attrs == 0) max_attrs = 0x0FFFFFFF; |
653 | |
|
654 | 0 | ctrl->oid = LDB_CONTROL_DIRSYNC_EX_OID; |
655 | 0 | ctrl->critical = crit; |
656 | 0 | control = talloc(ctrl, struct ldb_dirsync_control); |
657 | 0 | if (control == NULL) { |
658 | 0 | ldb_oom(ldb); |
659 | 0 | talloc_free(ctrl); |
660 | 0 | return NULL; |
661 | 0 | } |
662 | 0 | control->flags = flags; |
663 | 0 | control->max_attributes = max_attrs; |
664 | 0 | if (*cookie) { |
665 | 0 | int len = ldb_base64_decode(cookie); |
666 | 0 | if (len < 0) { |
667 | 0 | ldb_set_errstring(ldb, |
668 | 0 | "invalid dirsync_ex cookie" |
669 | 0 | " (probably too long)\n"); |
670 | 0 | talloc_free(ctrl); |
671 | 0 | return NULL; |
672 | 0 | } |
673 | 0 | control->cookie_len = len; |
674 | 0 | control->cookie = (char *)talloc_memdup(control, cookie, control->cookie_len); |
675 | 0 | if (control->cookie == NULL) { |
676 | 0 | ldb_oom(ldb); |
677 | 0 | talloc_free(ctrl); |
678 | 0 | return NULL; |
679 | 0 | } |
680 | 0 | } else { |
681 | 0 | control->cookie = NULL; |
682 | 0 | control->cookie_len = 0; |
683 | 0 | } |
684 | 0 | ctrl->data = control; |
685 | 0 | TALLOC_FREE(cookie); |
686 | |
|
687 | 0 | return ctrl; |
688 | 0 | } |
689 | | |
690 | 0 | if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_ASQ_NAME) == 0) { |
691 | 0 | struct ldb_asq_control *control; |
692 | 0 | const char *p; |
693 | 0 | char attr[256]; |
694 | 0 | int crit, ret; |
695 | |
|
696 | 0 | attr[0] = '\0'; |
697 | 0 | p = &(control_strings[sizeof(LDB_CONTROL_ASQ_NAME)]); |
698 | 0 | ret = sscanf(p, "%d:%255[^$]", &crit, attr); |
699 | 0 | if ((ret != 2) || (crit < 0) || (crit > 1) || (attr[0] == '\0')) { |
700 | 0 | ldb_set_errstring(ldb, |
701 | 0 | "invalid asq control syntax\n" |
702 | 0 | " syntax: crit(b):attr(s)\n" |
703 | 0 | " note: b = boolean, s = string"); |
704 | 0 | talloc_free(ctrl); |
705 | 0 | return NULL; |
706 | 0 | } |
707 | | |
708 | 0 | ctrl->oid = LDB_CONTROL_ASQ_OID; |
709 | 0 | ctrl->critical = crit; |
710 | 0 | control = talloc(ctrl, struct ldb_asq_control); |
711 | 0 | if (control == NULL) { |
712 | 0 | ldb_oom(ldb); |
713 | 0 | talloc_free(ctrl); |
714 | 0 | return NULL; |
715 | 0 | } |
716 | 0 | control->request = 1; |
717 | 0 | control->source_attribute = talloc_strdup(control, attr); |
718 | 0 | control->src_attr_len = strlen(attr); |
719 | 0 | ctrl->data = control; |
720 | |
|
721 | 0 | return ctrl; |
722 | 0 | } |
723 | | |
724 | 0 | if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_EXTENDED_DN_NAME) == 0) { |
725 | 0 | struct ldb_extended_dn_control *control; |
726 | 0 | const char *p; |
727 | 0 | int crit, type, ret; |
728 | |
|
729 | 0 | p = &(control_strings[sizeof(LDB_CONTROL_EXTENDED_DN_NAME)]); |
730 | 0 | ret = sscanf(p, "%d:%d", &crit, &type); |
731 | 0 | if ((ret != 2) || (crit < 0) || (crit > 1) || (type < 0) || (type > 1)) { |
732 | 0 | ret = sscanf(p, "%d", &crit); |
733 | 0 | if ((ret != 1) || (crit < 0) || (crit > 1)) { |
734 | 0 | ldb_set_errstring(ldb, |
735 | 0 | "invalid extended_dn control syntax\n" |
736 | 0 | " syntax: crit(b)[:type(i)]\n" |
737 | 0 | " note: b = boolean\n" |
738 | 0 | " i = integer\n" |
739 | 0 | " valid values are: 0 - hexadecimal representation\n" |
740 | 0 | " 1 - normal string representation"); |
741 | 0 | talloc_free(ctrl); |
742 | 0 | return NULL; |
743 | 0 | } |
744 | 0 | control = NULL; |
745 | 0 | } else { |
746 | 0 | control = talloc(ctrl, struct ldb_extended_dn_control); |
747 | 0 | if (control == NULL) { |
748 | 0 | ldb_oom(ldb); |
749 | 0 | talloc_free(ctrl); |
750 | 0 | return NULL; |
751 | 0 | } |
752 | 0 | control->type = type; |
753 | 0 | } |
754 | | |
755 | 0 | ctrl->oid = LDB_CONTROL_EXTENDED_DN_OID; |
756 | 0 | ctrl->critical = crit; |
757 | 0 | ctrl->data = control; |
758 | |
|
759 | 0 | return ctrl; |
760 | 0 | } |
761 | | |
762 | 0 | if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_SD_FLAGS_NAME) == 0) { |
763 | 0 | struct ldb_sd_flags_control *control; |
764 | 0 | const char *p; |
765 | 0 | int crit, ret; |
766 | 0 | unsigned secinfo_flags; |
767 | |
|
768 | 0 | p = &(control_strings[sizeof(LDB_CONTROL_SD_FLAGS_NAME)]); |
769 | 0 | ret = sscanf(p, "%d:%u", &crit, &secinfo_flags); |
770 | 0 | if ((ret != 2) || (crit < 0) || (crit > 1) || (secinfo_flags > 0xF)) { |
771 | 0 | ldb_set_errstring(ldb, |
772 | 0 | "invalid sd_flags control syntax\n" |
773 | 0 | " syntax: crit(b):secinfo_flags(n)\n" |
774 | 0 | " note: b = boolean, n = number"); |
775 | 0 | talloc_free(ctrl); |
776 | 0 | return NULL; |
777 | 0 | } |
778 | | |
779 | 0 | ctrl->oid = LDB_CONTROL_SD_FLAGS_OID; |
780 | 0 | ctrl->critical = crit; |
781 | 0 | control = talloc(ctrl, struct ldb_sd_flags_control); |
782 | 0 | if (control == NULL) { |
783 | 0 | ldb_oom(ldb); |
784 | 0 | talloc_free(ctrl); |
785 | 0 | return NULL; |
786 | 0 | } |
787 | | |
788 | 0 | control->secinfo_flags = secinfo_flags; |
789 | 0 | ctrl->data = control; |
790 | |
|
791 | 0 | return ctrl; |
792 | 0 | } |
793 | | |
794 | 0 | if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_SEARCH_OPTIONS_NAME) == 0) { |
795 | 0 | struct ldb_search_options_control *control; |
796 | 0 | const char *p; |
797 | 0 | int crit, ret; |
798 | 0 | unsigned search_options; |
799 | |
|
800 | 0 | p = &(control_strings[sizeof(LDB_CONTROL_SEARCH_OPTIONS_NAME)]); |
801 | 0 | ret = sscanf(p, "%d:%u", &crit, &search_options); |
802 | 0 | if ((ret != 2) || (crit < 0) || (crit > 1) || (search_options > 0xF)) { |
803 | 0 | ldb_set_errstring(ldb, |
804 | 0 | "invalid search_options control syntax\n" |
805 | 0 | " syntax: crit(b):search_options(n)\n" |
806 | 0 | " note: b = boolean, n = number"); |
807 | 0 | talloc_free(ctrl); |
808 | 0 | return NULL; |
809 | 0 | } |
810 | | |
811 | 0 | ctrl->oid = LDB_CONTROL_SEARCH_OPTIONS_OID; |
812 | 0 | ctrl->critical = crit; |
813 | 0 | control = talloc(ctrl, struct ldb_search_options_control); |
814 | 0 | if (control == NULL) { |
815 | 0 | ldb_oom(ldb); |
816 | 0 | talloc_free(ctrl); |
817 | 0 | return NULL; |
818 | 0 | } |
819 | | |
820 | 0 | control->search_options = search_options; |
821 | 0 | ctrl->data = control; |
822 | |
|
823 | 0 | return ctrl; |
824 | 0 | } |
825 | | |
826 | 0 | if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_BYPASS_OPERATIONAL_NAME) == 0) { |
827 | 0 | const char *p; |
828 | 0 | int crit, ret; |
829 | |
|
830 | 0 | p = &(control_strings[sizeof(LDB_CONTROL_BYPASS_OPERATIONAL_NAME)]); |
831 | 0 | ret = sscanf(p, "%d", &crit); |
832 | 0 | if ((ret != 1) || (crit < 0) || (crit > 1)) { |
833 | 0 | ldb_set_errstring(ldb, |
834 | 0 | "invalid bypassoperational control syntax\n" |
835 | 0 | " syntax: crit(b)\n" |
836 | 0 | " note: b = boolean"); |
837 | 0 | talloc_free(ctrl); |
838 | 0 | return NULL; |
839 | 0 | } |
840 | | |
841 | 0 | ctrl->oid = LDB_CONTROL_BYPASS_OPERATIONAL_OID; |
842 | 0 | ctrl->critical = crit; |
843 | 0 | ctrl->data = NULL; |
844 | |
|
845 | 0 | return ctrl; |
846 | 0 | } |
847 | | |
848 | 0 | if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_RELAX_NAME) == 0) { |
849 | 0 | const char *p; |
850 | 0 | int crit, ret; |
851 | |
|
852 | 0 | p = &(control_strings[sizeof(LDB_CONTROL_RELAX_NAME)]); |
853 | 0 | ret = sscanf(p, "%d", &crit); |
854 | 0 | if ((ret != 1) || (crit < 0) || (crit > 1)) { |
855 | 0 | ldb_set_errstring(ldb, |
856 | 0 | "invalid relax control syntax\n" |
857 | 0 | " syntax: crit(b)\n" |
858 | 0 | " note: b = boolean"); |
859 | 0 | talloc_free(ctrl); |
860 | 0 | return NULL; |
861 | 0 | } |
862 | | |
863 | 0 | ctrl->oid = LDB_CONTROL_RELAX_OID; |
864 | 0 | ctrl->critical = crit; |
865 | 0 | ctrl->data = NULL; |
866 | |
|
867 | 0 | return ctrl; |
868 | 0 | } |
869 | | |
870 | 0 | if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_RECALCULATE_SD_NAME) == 0) { |
871 | 0 | const char *p; |
872 | 0 | int crit, ret; |
873 | |
|
874 | 0 | p = &(control_strings[sizeof(LDB_CONTROL_RECALCULATE_SD_NAME)]); |
875 | 0 | ret = sscanf(p, "%d", &crit); |
876 | 0 | if ((ret != 1) || (crit < 0) || (crit > 1)) { |
877 | 0 | ldb_set_errstring(ldb, |
878 | 0 | "invalid recalculate_sd control syntax\n" |
879 | 0 | " syntax: crit(b)\n" |
880 | 0 | " note: b = boolean"); |
881 | 0 | talloc_free(ctrl); |
882 | 0 | return NULL; |
883 | 0 | } |
884 | | |
885 | 0 | ctrl->oid = LDB_CONTROL_RECALCULATE_SD_OID; |
886 | 0 | ctrl->critical = crit; |
887 | 0 | ctrl->data = NULL; |
888 | |
|
889 | 0 | return ctrl; |
890 | 0 | } |
891 | | |
892 | 0 | if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_DOMAIN_SCOPE_NAME) == 0) { |
893 | 0 | const char *p; |
894 | 0 | int crit, ret; |
895 | |
|
896 | 0 | p = &(control_strings[sizeof(LDB_CONTROL_DOMAIN_SCOPE_NAME)]); |
897 | 0 | ret = sscanf(p, "%d", &crit); |
898 | 0 | if ((ret != 1) || (crit < 0) || (crit > 1)) { |
899 | 0 | ldb_set_errstring(ldb, |
900 | 0 | "invalid domain_scope control syntax\n" |
901 | 0 | " syntax: crit(b)\n" |
902 | 0 | " note: b = boolean"); |
903 | 0 | talloc_free(ctrl); |
904 | 0 | return NULL; |
905 | 0 | } |
906 | | |
907 | 0 | ctrl->oid = LDB_CONTROL_DOMAIN_SCOPE_OID; |
908 | 0 | ctrl->critical = crit; |
909 | 0 | ctrl->data = NULL; |
910 | |
|
911 | 0 | return ctrl; |
912 | 0 | } |
913 | | |
914 | 0 | if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_PAGED_RESULTS_NAME) == 0) { |
915 | 0 | struct ldb_paged_control *control; |
916 | 0 | const char *p; |
917 | 0 | char cookie[1024]; |
918 | 0 | int crit, size, ret; |
919 | |
|
920 | 0 | cookie[0] = '\0'; |
921 | 0 | p = &(control_strings[sizeof(LDB_CONTROL_PAGED_RESULTS_NAME)]); |
922 | 0 | ret = sscanf(p, "%d:%d:%1023[^$]", &crit, &size, cookie); |
923 | 0 | if ((ret < 2) || (ret > 3) || (crit < 0) || (crit > 1) || |
924 | 0 | (size < 0)) { |
925 | 0 | ldb_set_errstring(ldb, |
926 | 0 | "invalid paged_results control syntax\n" |
927 | 0 | " syntax: crit(b):size(n)[:cookie(base64)]\n" |
928 | 0 | " note: b = boolean, n = number"); |
929 | 0 | talloc_free(ctrl); |
930 | 0 | return NULL; |
931 | 0 | } |
932 | | |
933 | 0 | ctrl->oid = LDB_CONTROL_PAGED_RESULTS_OID; |
934 | 0 | ctrl->critical = crit; |
935 | 0 | control = talloc(ctrl, struct ldb_paged_control); |
936 | 0 | if (control == NULL) { |
937 | 0 | ldb_oom(ldb); |
938 | 0 | talloc_free(ctrl); |
939 | 0 | return NULL; |
940 | 0 | } |
941 | | |
942 | 0 | control->size = size; |
943 | 0 | if (cookie[0] != '\0') { |
944 | 0 | int len = ldb_base64_decode(cookie); |
945 | 0 | if (len < 0) { |
946 | 0 | ldb_set_errstring(ldb, |
947 | 0 | "invalid paged_results cookie" |
948 | 0 | " (probably too long)\n"); |
949 | 0 | talloc_free(ctrl); |
950 | 0 | return NULL; |
951 | 0 | } |
952 | 0 | control->cookie_len = len; |
953 | 0 | control->cookie = talloc_memdup(control, cookie, control->cookie_len); |
954 | 0 | if (control->cookie == NULL) { |
955 | 0 | ldb_oom(ldb); |
956 | 0 | talloc_free(ctrl); |
957 | 0 | return NULL; |
958 | 0 | } |
959 | 0 | } else { |
960 | 0 | control->cookie = NULL; |
961 | 0 | control->cookie_len = 0; |
962 | 0 | } |
963 | 0 | ctrl->data = control; |
964 | |
|
965 | 0 | return ctrl; |
966 | 0 | } |
967 | | |
968 | 0 | if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_SERVER_SORT_NAME) == 0) { |
969 | 0 | struct ldb_server_sort_control **control; |
970 | 0 | const char *p; |
971 | 0 | char attr[256]; |
972 | 0 | char rule[128]; |
973 | 0 | int crit, rev, ret; |
974 | |
|
975 | 0 | attr[0] = '\0'; |
976 | 0 | rule[0] = '\0'; |
977 | 0 | p = &(control_strings[sizeof(LDB_CONTROL_SERVER_SORT_NAME)]); |
978 | 0 | ret = sscanf(p, "%d:%d:%255[^:]:%127[^:]", &crit, &rev, attr, rule); |
979 | 0 | if ((ret < 3) || (crit < 0) || (crit > 1) || (rev < 0 ) || (rev > 1) ||attr[0] == '\0') { |
980 | 0 | ldb_set_errstring(ldb, |
981 | 0 | "invalid server_sort control syntax\n" |
982 | 0 | " syntax: crit(b):rev(b):attr(s)[:rule(s)]\n" |
983 | 0 | " note: b = boolean, s = string"); |
984 | 0 | talloc_free(ctrl); |
985 | 0 | return NULL; |
986 | 0 | } |
987 | 0 | ctrl->oid = LDB_CONTROL_SERVER_SORT_OID; |
988 | 0 | ctrl->critical = crit; |
989 | 0 | control = talloc_array(ctrl, struct ldb_server_sort_control *, 2); |
990 | 0 | if (control == NULL) { |
991 | 0 | ldb_oom(ldb); |
992 | 0 | talloc_free(ctrl); |
993 | 0 | return NULL; |
994 | 0 | } |
995 | | |
996 | 0 | control[0] = talloc(control, struct ldb_server_sort_control); |
997 | 0 | if (control[0] == NULL) { |
998 | 0 | ldb_oom(ldb); |
999 | 0 | talloc_free(ctrl); |
1000 | 0 | return NULL; |
1001 | 0 | } |
1002 | | |
1003 | 0 | control[0]->attributeName = talloc_strdup(control, attr); |
1004 | 0 | if (control[0]->attributeName == NULL) { |
1005 | 0 | ldb_oom(ldb); |
1006 | 0 | talloc_free(ctrl); |
1007 | 0 | return NULL; |
1008 | 0 | } |
1009 | | |
1010 | 0 | if (rule[0]) { |
1011 | 0 | control[0]->orderingRule = talloc_strdup(control, rule); |
1012 | 0 | if (control[0]->orderingRule == NULL) { |
1013 | 0 | ldb_oom(ldb); |
1014 | 0 | talloc_free(ctrl); |
1015 | 0 | return NULL; |
1016 | 0 | } |
1017 | 0 | } else { |
1018 | 0 | control[0]->orderingRule = NULL; |
1019 | 0 | } |
1020 | 0 | control[0]->reverse = rev; |
1021 | 0 | control[1] = NULL; |
1022 | 0 | ctrl->data = control; |
1023 | |
|
1024 | 0 | return ctrl; |
1025 | 0 | } |
1026 | | |
1027 | 0 | if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_NOTIFICATION_NAME) == 0) { |
1028 | 0 | const char *p; |
1029 | 0 | int crit, ret; |
1030 | |
|
1031 | 0 | p = &(control_strings[sizeof(LDB_CONTROL_NOTIFICATION_NAME)]); |
1032 | 0 | ret = sscanf(p, "%d", &crit); |
1033 | 0 | if ((ret != 1) || (crit < 0) || (crit > 1)) { |
1034 | 0 | ldb_set_errstring(ldb, |
1035 | 0 | "invalid notification control syntax\n" |
1036 | 0 | " syntax: crit(b)\n" |
1037 | 0 | " note: b = boolean"); |
1038 | 0 | talloc_free(ctrl); |
1039 | 0 | return NULL; |
1040 | 0 | } |
1041 | | |
1042 | 0 | ctrl->oid = LDB_CONTROL_NOTIFICATION_OID; |
1043 | 0 | ctrl->critical = crit; |
1044 | 0 | ctrl->data = NULL; |
1045 | |
|
1046 | 0 | return ctrl; |
1047 | 0 | } |
1048 | | |
1049 | 0 | if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_TREE_DELETE_NAME) == 0) { |
1050 | 0 | const char *p; |
1051 | 0 | int crit, ret; |
1052 | |
|
1053 | 0 | p = &(control_strings[sizeof(LDB_CONTROL_TREE_DELETE_NAME)]); |
1054 | 0 | ret = sscanf(p, "%d", &crit); |
1055 | 0 | if ((ret != 1) || (crit < 0) || (crit > 1)) { |
1056 | 0 | ldb_set_errstring(ldb, |
1057 | 0 | "invalid tree_delete control syntax\n" |
1058 | 0 | " syntax: crit(b)\n" |
1059 | 0 | " note: b = boolean"); |
1060 | 0 | talloc_free(ctrl); |
1061 | 0 | return NULL; |
1062 | 0 | } |
1063 | | |
1064 | 0 | ctrl->oid = LDB_CONTROL_TREE_DELETE_OID; |
1065 | 0 | ctrl->critical = crit; |
1066 | 0 | ctrl->data = NULL; |
1067 | |
|
1068 | 0 | return ctrl; |
1069 | 0 | } |
1070 | | |
1071 | 0 | if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_SHOW_DELETED_NAME) == 0) { |
1072 | 0 | const char *p; |
1073 | 0 | int crit, ret; |
1074 | |
|
1075 | 0 | p = &(control_strings[sizeof(LDB_CONTROL_SHOW_DELETED_NAME)]); |
1076 | 0 | ret = sscanf(p, "%d", &crit); |
1077 | 0 | if ((ret != 1) || (crit < 0) || (crit > 1)) { |
1078 | 0 | ldb_set_errstring(ldb, |
1079 | 0 | "invalid show_deleted control syntax\n" |
1080 | 0 | " syntax: crit(b)\n" |
1081 | 0 | " note: b = boolean"); |
1082 | 0 | talloc_free(ctrl); |
1083 | 0 | return NULL; |
1084 | 0 | } |
1085 | | |
1086 | 0 | ctrl->oid = LDB_CONTROL_SHOW_DELETED_OID; |
1087 | 0 | ctrl->critical = crit; |
1088 | 0 | ctrl->data = NULL; |
1089 | |
|
1090 | 0 | return ctrl; |
1091 | 0 | } |
1092 | | |
1093 | 0 | if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_SHOW_DEACTIVATED_LINK_NAME) == 0) { |
1094 | 0 | const char *p; |
1095 | 0 | int crit, ret; |
1096 | |
|
1097 | 0 | p = &(control_strings[sizeof(LDB_CONTROL_SHOW_DEACTIVATED_LINK_NAME)]); |
1098 | 0 | ret = sscanf(p, "%d", &crit); |
1099 | 0 | if ((ret != 1) || (crit < 0) || (crit > 1)) { |
1100 | 0 | ldb_set_errstring(ldb, |
1101 | 0 | "invalid show_deactivated_link control syntax\n" |
1102 | 0 | " syntax: crit(b)\n" |
1103 | 0 | " note: b = boolean"); |
1104 | 0 | talloc_free(ctrl); |
1105 | 0 | return NULL; |
1106 | 0 | } |
1107 | | |
1108 | 0 | ctrl->oid = LDB_CONTROL_SHOW_DEACTIVATED_LINK_OID; |
1109 | 0 | ctrl->critical = crit; |
1110 | 0 | ctrl->data = NULL; |
1111 | |
|
1112 | 0 | return ctrl; |
1113 | 0 | } |
1114 | | |
1115 | 0 | if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_SHOW_RECYCLED_NAME) == 0) { |
1116 | 0 | const char *p; |
1117 | 0 | int crit, ret; |
1118 | |
|
1119 | 0 | p = &(control_strings[sizeof(LDB_CONTROL_SHOW_RECYCLED_NAME)]); |
1120 | 0 | ret = sscanf(p, "%d", &crit); |
1121 | 0 | if ((ret != 1) || (crit < 0) || (crit > 1)) { |
1122 | 0 | ldb_set_errstring(ldb, |
1123 | 0 | "invalid show_recycled control syntax\n" |
1124 | 0 | " syntax: crit(b)\n" |
1125 | 0 | " note: b = boolean"); |
1126 | 0 | talloc_free(ctrl); |
1127 | 0 | return NULL; |
1128 | 0 | } |
1129 | | |
1130 | 0 | ctrl->oid = LDB_CONTROL_SHOW_RECYCLED_OID; |
1131 | 0 | ctrl->critical = crit; |
1132 | 0 | ctrl->data = NULL; |
1133 | |
|
1134 | 0 | return ctrl; |
1135 | 0 | } |
1136 | | |
1137 | 0 | if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_PERMISSIVE_MODIFY_NAME) == 0) { |
1138 | 0 | const char *p; |
1139 | 0 | int crit, ret; |
1140 | |
|
1141 | 0 | p = &(control_strings[sizeof(LDB_CONTROL_PERMISSIVE_MODIFY_NAME)]); |
1142 | 0 | ret = sscanf(p, "%d", &crit); |
1143 | 0 | if ((ret != 1) || (crit < 0) || (crit > 1)) { |
1144 | 0 | ldb_set_errstring(ldb, |
1145 | 0 | "invalid permissive_modify control syntax\n" |
1146 | 0 | " syntax: crit(b)\n" |
1147 | 0 | " note: b = boolean"); |
1148 | 0 | talloc_free(ctrl); |
1149 | 0 | return NULL; |
1150 | 0 | } |
1151 | | |
1152 | 0 | ctrl->oid = LDB_CONTROL_PERMISSIVE_MODIFY_OID; |
1153 | 0 | ctrl->critical = crit; |
1154 | 0 | ctrl->data = NULL; |
1155 | |
|
1156 | 0 | return ctrl; |
1157 | 0 | } |
1158 | | |
1159 | 0 | if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_REVEAL_INTERNALS_NAME) == 0) { |
1160 | 0 | const char *p; |
1161 | 0 | int crit, ret; |
1162 | |
|
1163 | 0 | p = &(control_strings[sizeof(LDB_CONTROL_REVEAL_INTERNALS_NAME)]); |
1164 | 0 | ret = sscanf(p, "%d", &crit); |
1165 | 0 | if ((ret != 1) || (crit < 0) || (crit > 1)) { |
1166 | 0 | ldb_set_errstring(ldb, |
1167 | 0 | "invalid reveal_internals control syntax\n" |
1168 | 0 | " syntax: crit(b)\n" |
1169 | 0 | " note: b = boolean"); |
1170 | 0 | talloc_free(ctrl); |
1171 | 0 | return NULL; |
1172 | 0 | } |
1173 | | |
1174 | 0 | ctrl->oid = LDB_CONTROL_REVEAL_INTERNALS; |
1175 | 0 | ctrl->critical = crit; |
1176 | 0 | ctrl->data = NULL; |
1177 | |
|
1178 | 0 | return ctrl; |
1179 | 0 | } |
1180 | | |
1181 | 0 | if (strncmp(control_strings, "local_oid:", 10) == 0) { |
1182 | 0 | const char *p; |
1183 | 0 | int crit = 0, ret = 0; |
1184 | 0 | char oid[256]; |
1185 | |
|
1186 | 0 | oid[0] = '\0'; |
1187 | 0 | p = &(control_strings[10]); |
1188 | 0 | ret = sscanf(p, "%255[^:]:%d", oid, &crit); |
1189 | |
|
1190 | 0 | if ((ret != 2) || strlen(oid) == 0 || (crit < 0) || (crit > 1)) { |
1191 | 0 | ldb_set_errstring(ldb, |
1192 | 0 | "invalid local_oid control syntax\n" |
1193 | 0 | " syntax: oid(s):crit(b)\n" |
1194 | 0 | " note: b = boolean, s = string"); |
1195 | 0 | talloc_free(ctrl); |
1196 | 0 | return NULL; |
1197 | 0 | } |
1198 | | |
1199 | 0 | ctrl->oid = talloc_strdup(ctrl, oid); |
1200 | 0 | if (!ctrl->oid) { |
1201 | 0 | ldb_oom(ldb); |
1202 | 0 | talloc_free(ctrl); |
1203 | 0 | return NULL; |
1204 | 0 | } |
1205 | 0 | ctrl->critical = crit; |
1206 | 0 | ctrl->data = NULL; |
1207 | |
|
1208 | 0 | return ctrl; |
1209 | 0 | } |
1210 | | |
1211 | 0 | if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_RODC_DCPROMO_NAME) == 0) { |
1212 | 0 | const char *p; |
1213 | 0 | int crit, ret; |
1214 | |
|
1215 | 0 | p = &(control_strings[sizeof(LDB_CONTROL_RODC_DCPROMO_NAME)]); |
1216 | 0 | ret = sscanf(p, "%d", &crit); |
1217 | 0 | if ((ret != 1) || (crit < 0) || (crit > 1)) { |
1218 | 0 | ldb_set_errstring(ldb, |
1219 | 0 | "invalid rodc_join control syntax\n" |
1220 | 0 | " syntax: crit(b)\n" |
1221 | 0 | " note: b = boolean"); |
1222 | 0 | talloc_free(ctrl); |
1223 | 0 | return NULL; |
1224 | 0 | } |
1225 | | |
1226 | 0 | ctrl->oid = LDB_CONTROL_RODC_DCPROMO_OID; |
1227 | 0 | ctrl->critical = crit; |
1228 | 0 | ctrl->data = NULL; |
1229 | |
|
1230 | 0 | return ctrl; |
1231 | 0 | } |
1232 | | |
1233 | 0 | if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_PROVISION_NAME) == 0) { |
1234 | 0 | const char *p; |
1235 | 0 | int crit, ret; |
1236 | |
|
1237 | 0 | p = &(control_strings[sizeof(LDB_CONTROL_PROVISION_NAME)]); |
1238 | 0 | ret = sscanf(p, "%d", &crit); |
1239 | 0 | if ((ret != 1) || (crit < 0) || (crit > 1)) { |
1240 | 0 | ldb_set_errstring(ldb, |
1241 | 0 | "invalid provision control syntax\n" |
1242 | 0 | " syntax: crit(b)\n" |
1243 | 0 | " note: b = boolean"); |
1244 | 0 | talloc_free(ctrl); |
1245 | 0 | return NULL; |
1246 | 0 | } |
1247 | | |
1248 | 0 | ctrl->oid = LDB_CONTROL_PROVISION_OID; |
1249 | 0 | ctrl->critical = crit; |
1250 | 0 | ctrl->data = NULL; |
1251 | |
|
1252 | 0 | return ctrl; |
1253 | 0 | } |
1254 | 0 | if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_VERIFY_NAME_NAME) == 0) { |
1255 | 0 | const char *p; |
1256 | 0 | char gc[1024]; |
1257 | 0 | int crit, flags, ret; |
1258 | 0 | struct ldb_verify_name_control *control; |
1259 | |
|
1260 | 0 | gc[0] = '\0'; |
1261 | |
|
1262 | 0 | p = &(control_strings[sizeof(LDB_CONTROL_VERIFY_NAME_NAME)]); |
1263 | 0 | ret = sscanf(p, "%d:%d:%1023[^$]", &crit, &flags, gc); |
1264 | 0 | if ((ret != 3) || (crit < 0) || (crit > 1)) { |
1265 | 0 | ret = sscanf(p, "%d:%d", &crit, &flags); |
1266 | 0 | if ((ret != 2) || (crit < 0) || (crit > 1)) { |
1267 | 0 | ldb_set_errstring(ldb, |
1268 | 0 | "invalid verify_name control syntax\n" |
1269 | 0 | " syntax: crit(b):flags(i)[:gc(s)]\n" |
1270 | 0 | " note: b = boolean" |
1271 | 0 | " note: i = integer" |
1272 | 0 | " note: s = string"); |
1273 | 0 | talloc_free(ctrl); |
1274 | 0 | return NULL; |
1275 | 0 | } |
1276 | 0 | } |
1277 | | |
1278 | 0 | ctrl->oid = LDB_CONTROL_VERIFY_NAME_OID; |
1279 | 0 | ctrl->critical = crit; |
1280 | 0 | control = talloc(ctrl, struct ldb_verify_name_control); |
1281 | 0 | if (control == NULL) { |
1282 | 0 | ldb_oom(ldb); |
1283 | 0 | talloc_free(ctrl); |
1284 | 0 | return NULL; |
1285 | 0 | } |
1286 | | |
1287 | 0 | control->gc = talloc_strdup(control, gc); |
1288 | 0 | if (control->gc == NULL) { |
1289 | 0 | ldb_oom(ldb); |
1290 | 0 | talloc_free(ctrl); |
1291 | 0 | return NULL; |
1292 | 0 | } |
1293 | | |
1294 | 0 | control->gc_len = strlen(gc); |
1295 | 0 | control->flags = flags; |
1296 | 0 | ctrl->data = control; |
1297 | 0 | return ctrl; |
1298 | 0 | } |
1299 | | |
1300 | 0 | if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_POLICY_HINTS_NAME) == 0) { |
1301 | 0 | const char *p = NULL; |
1302 | 0 | int crit, val, ret; |
1303 | |
|
1304 | 0 | p = &(control_strings[sizeof(LDB_CONTROL_POLICY_HINTS_NAME)]); |
1305 | 0 | ret = sscanf(p, "%d:%d", &crit, &val); |
1306 | 0 | if ((ret != 2) || (crit < 0) || (crit > 1)) { |
1307 | 0 | ldb_set_errstring(ldb, |
1308 | 0 | "invalid pwd_policy_hints control syntax\n" |
1309 | 0 | " syntax: crit(b):flags(n)\n" |
1310 | 0 | " note: b = boolean, n = number"); |
1311 | 0 | talloc_free(ctrl); |
1312 | 0 | return NULL; |
1313 | 0 | } |
1314 | | |
1315 | 0 | ctrl->oid = LDB_CONTROL_POLICY_HINTS_OID; |
1316 | 0 | ctrl->critical = crit; |
1317 | 0 | ctrl->data = talloc(ctrl, int); |
1318 | 0 | *((int*)ctrl->data) = val; |
1319 | 0 | return ctrl; |
1320 | 0 | } |
1321 | | |
1322 | 0 | if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_POLICY_HINTS_DEPRECATED_NAME) == 0) { |
1323 | 0 | const char *p = NULL; |
1324 | 0 | int crit, val, ret; |
1325 | |
|
1326 | 0 | p = &(control_strings[sizeof(LDB_CONTROL_POLICY_HINTS_DEPRECATED_NAME)]); |
1327 | 0 | ret = sscanf(p, "%d:%d", &crit, &val); |
1328 | 0 | if ((ret != 2) || (crit < 0) || (crit > 1)) { |
1329 | 0 | ldb_set_errstring(ldb, |
1330 | 0 | "invalid pwd_policy_hints control syntax\n" |
1331 | 0 | " syntax: crit(b):flags(n)\n" |
1332 | 0 | " note: b = boolean, n = number"); |
1333 | 0 | talloc_free(ctrl); |
1334 | 0 | return NULL; |
1335 | 0 | } |
1336 | | |
1337 | 0 | ctrl->oid = LDB_CONTROL_POLICY_HINTS_DEPRECATED_OID; |
1338 | 0 | ctrl->critical = crit; |
1339 | 0 | ctrl->data = talloc(ctrl, int); |
1340 | 0 | *((int*)ctrl->data) = val; |
1341 | 0 | return ctrl; |
1342 | 0 | } |
1343 | | |
1344 | | |
1345 | | /* |
1346 | | * When no matching control has been found. |
1347 | | */ |
1348 | 0 | TALLOC_FREE(ctrl); |
1349 | 0 | return NULL; |
1350 | 0 | } |
1351 | | |
1352 | | /* Parse controls from the format used on the command line and in ejs */ |
1353 | | struct ldb_control **ldb_parse_control_strings(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char **control_strings) |
1354 | 0 | { |
1355 | 0 | unsigned int i; |
1356 | 0 | struct ldb_control **ctrl; |
1357 | |
|
1358 | 0 | if (control_strings == NULL || control_strings[0] == NULL) |
1359 | 0 | return NULL; |
1360 | | |
1361 | 0 | for (i = 0; control_strings[i]; i++); |
1362 | |
|
1363 | 0 | ctrl = talloc_array(mem_ctx, struct ldb_control *, i + 1); |
1364 | |
|
1365 | 0 | ldb_reset_err_string(ldb); |
1366 | 0 | for (i = 0; control_strings[i]; i++) { |
1367 | 0 | ctrl[i] = ldb_parse_control_from_string(ldb, ctrl, control_strings[i]); |
1368 | 0 | if (ctrl[i] == NULL) { |
1369 | 0 | if (ldb_errstring(ldb) == NULL) { |
1370 | | /* no controls matched, throw an error */ |
1371 | 0 | ldb_asprintf_errstring(ldb, "Invalid control name: '%s'", control_strings[i]); |
1372 | 0 | } |
1373 | 0 | talloc_free(ctrl); |
1374 | 0 | return NULL; |
1375 | 0 | } |
1376 | 0 | } |
1377 | | |
1378 | 0 | ctrl[i] = NULL; |
1379 | |
|
1380 | 0 | return ctrl; |
1381 | 0 | } |