137d35ac4e47b7d1b84d1020bcb43af7ddbd5996
[samba.git] / source4 / lib / ldb / common / ldb_controls.c
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_includes.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_request_get_control(struct ldb_request *req, const char *oid)
39 {
40         int i;
41
42         /* check if there's a paged request control */
43         if (req->controls != NULL) {
44                 for (i = 0; req->controls[i]; i++) {
45                         if (strcmp(oid, req->controls[i]->oid) == 0) {
46                                 break;
47                         }
48                 }
49
50                 return req->controls[i];
51         }
52
53         return NULL;
54 }
55
56 /* saves the current controls list into the "saver" and replace the one in req with a new one excluding
57 the "exclude" control */
58 /* returns False on error */
59 int save_controls(struct ldb_control *exclude, struct ldb_request *req, struct ldb_control ***saver)
60 {
61         struct ldb_control **lcs;
62         int i, j;
63
64         *saver = req->controls;
65         for (i = 0; req->controls[i]; i++);
66         if (i == 1) {
67                 req->controls = NULL;
68                 return 1;
69         }
70
71         lcs = talloc_array(req, struct ldb_control *, i);
72         if (!lcs) {
73                 return 0;
74         }
75
76         for (i = 0, j = 0; (*saver)[i]; i++) {
77                 if (exclude == (*saver)[i]) continue;
78                 lcs[j] = (*saver)[i];
79                 j++;
80         }
81         lcs[j] = NULL;
82
83         req->controls = lcs;
84         return 1;
85 }
86
87 /* check if there's any control marked as critical in the list */
88 /* return True if any, False if none */
89 int check_critical_controls(struct ldb_control **controls)
90 {
91         int i;
92
93         if (controls == NULL) {
94                 return 0;
95         }
96
97         for (i = 0; controls[i]; i++) {
98                 if (controls[i]->critical) {
99                         return 1;
100                 }
101         }
102
103         return 0;
104 }
105
106 int ldb_request_add_control(struct ldb_request *req, const char *oid, bool critical, void *data)
107 {
108         unsigned n;
109         struct ldb_control **ctrls;
110         struct ldb_control *ctrl;
111
112         for (n=0; req->controls && req->controls[n];) { n++; }
113
114         ctrls = talloc_realloc(req, req->controls,
115                                struct ldb_control *,
116                                n + 2);
117         if (!ctrls) return LDB_ERR_OPERATIONS_ERROR;
118         req->controls = ctrls;
119         ctrls[n] = NULL;
120         ctrls[n+1] = NULL;
121
122         ctrl = talloc(ctrls, struct ldb_control);
123         if (!ctrl) return LDB_ERR_OPERATIONS_ERROR;
124
125         ctrl->oid       = talloc_strdup(ctrl, oid);
126         if (!ctrl->oid) return LDB_ERR_OPERATIONS_ERROR;
127         ctrl->critical  = critical;
128         ctrl->data      = data;
129
130         ctrls[n] = ctrl;
131         return LDB_SUCCESS;
132 }
133
134 /* Parse controls from the format used on the command line and in ejs */
135
136 struct ldb_control **ldb_parse_control_strings(struct ldb_context *ldb, void *mem_ctx, const char **control_strings)
137 {
138         int i;
139         struct ldb_control **ctrl;
140
141         char *error_string = NULL;
142
143         if (control_strings == NULL || control_strings[0] == NULL)
144                 return NULL;
145
146         for (i = 0; control_strings[i]; i++);
147
148         ctrl = talloc_array(mem_ctx, struct ldb_control *, i + 1);
149
150         for (i = 0; control_strings[i]; i++) {
151                 if (strncmp(control_strings[i], "vlv:", 4) == 0) {
152                         struct ldb_vlv_req_control *control;
153                         const char *p;
154                         char attr[1024];
155                         char ctxid[1024];
156                         int crit, bc, ac, os, cc, ret;
157
158                         attr[0] = '\0';
159                         ctxid[0] = '\0';
160                         p = &(control_strings[i][4]);
161                         ret = sscanf(p, "%d:%d:%d:%d:%d:%1023[^$]", &crit, &bc, &ac, &os, &cc, ctxid);
162                         if (ret < 5) {
163                                 ret = sscanf(p, "%d:%d:%d:%1023[^:]:%1023[^$]", &crit, &bc, &ac, attr, ctxid);
164                         }
165                                
166                         if ((ret < 4) || (crit < 0) || (crit > 1)) {
167                                 error_string = talloc_asprintf(mem_ctx, "invalid server_sort control syntax\n");
168                                 error_string = talloc_asprintf_append(error_string, " syntax: crit(b):bc(n):ac(n):<os(n):cc(n)|attr(s)>[:ctxid(o)]\n");
169                                 error_string = talloc_asprintf_append(error_string, "   note: b = boolean, n = number, s = string, o = b64 binary blob");
170                                 ldb_set_errstring(ldb, error_string);
171                                 talloc_free(error_string);
172                                 return NULL;
173                         }
174                         if (!(ctrl[i] = talloc(ctrl, struct ldb_control))) {
175                                 ldb_oom(ldb);
176                                 return NULL;
177                         }
178                         ctrl[i]->oid = LDB_CONTROL_VLV_REQ_OID;
179                         ctrl[i]->critical = crit;
180                         if (!(control = talloc(ctrl[i],
181                                                struct ldb_vlv_req_control))) {
182                                 ldb_oom(ldb);
183                                 return NULL;
184                         }
185                         control->beforeCount = bc;
186                         control->afterCount = ac;
187                         if (attr[0]) {
188                                 control->type = 1;
189                                 control->match.gtOrEq.value = talloc_strdup(control, attr);
190                                 control->match.gtOrEq.value_len = strlen(attr);
191                         } else {
192                                 control->type = 0;
193                                 control->match.byOffset.offset = os;
194                                 control->match.byOffset.contentCount = cc;
195                         }
196                         if (ctxid[0]) {
197                                 control->ctxid_len = ldb_base64_decode(ctxid);
198                                 control->contextId = (char *)talloc_memdup(control, ctxid, control->ctxid_len);
199                         } else {
200                                 control->ctxid_len = 0;
201                                 control->contextId = NULL;
202                         }
203                         ctrl[i]->data = control;
204
205                         continue;
206                 }
207
208                 if (strncmp(control_strings[i], "dirsync:", 8) == 0) {
209                         struct ldb_dirsync_control *control;
210                         const char *p;
211                         char cookie[1024];
212                         int crit, flags, max_attrs, ret;
213                        
214                         cookie[0] = '\0';
215                         p = &(control_strings[i][8]);
216                         ret = sscanf(p, "%d:%d:%d:%1023[^$]", &crit, &flags, &max_attrs, cookie);
217
218                         if ((ret < 3) || (crit < 0) || (crit > 1) || (flags < 0) || (max_attrs < 0)) {
219                                 error_string = talloc_asprintf(mem_ctx, "invalid dirsync control syntax\n");
220                                 error_string = talloc_asprintf_append(error_string, " syntax: crit(b):flags(n):max_attrs(n)[:cookie(o)]\n");
221                                 error_string = talloc_asprintf_append(error_string, "   note: b = boolean, n = number, o = b64 binary blob");
222                                 ldb_set_errstring(ldb, error_string);
223                                 talloc_free(error_string);
224                                 return NULL;
225                         }
226
227                         /* w2k3 seems to ignore the parameter,
228                          * but w2k sends a wrong cookie when this value is to small
229                          * this would cause looping forever, while getting
230                          * the same data and same cookie forever
231                          */
232                         if (max_attrs == 0) max_attrs = 0x0FFFFFFF;
233
234                         ctrl[i] = talloc(ctrl, struct ldb_control);
235                         ctrl[i]->oid = LDB_CONTROL_DIRSYNC_OID;
236                         ctrl[i]->critical = crit;
237                         control = talloc(ctrl[i], struct ldb_dirsync_control);
238                         control->flags = flags;
239                         control->max_attributes = max_attrs;
240                         if (*cookie) {
241                                 control->cookie_len = ldb_base64_decode(cookie);
242                                 control->cookie = (char *)talloc_memdup(control, cookie, control->cookie_len);
243                         } else {
244                                 control->cookie = NULL;
245                                 control->cookie_len = 0;
246                         }
247                         ctrl[i]->data = control;
248
249                         continue;
250                 }
251
252                 if (strncmp(control_strings[i], "asq:", 4) == 0) {
253                         struct ldb_asq_control *control;
254                         const char *p;
255                         char attr[256];
256                         int crit, ret;
257
258                         attr[0] = '\0';
259                         p = &(control_strings[i][4]);
260                         ret = sscanf(p, "%d:%255[^$]", &crit, attr);
261                         if ((ret != 2) || (crit < 0) || (crit > 1) || (attr[0] == '\0')) {
262                                 error_string = talloc_asprintf(mem_ctx, "invalid asq control syntax\n");
263                                 error_string = talloc_asprintf_append(error_string, " syntax: crit(b):attr(s)\n");
264                                 error_string = talloc_asprintf_append(error_string, "   note: b = boolean, s = string");
265                                 ldb_set_errstring(ldb, error_string);
266                                 talloc_free(error_string);
267                                 return NULL;
268                         }
269
270                         ctrl[i] = talloc(ctrl, struct ldb_control);
271                         if (!ctrl[i]) {
272                                 ldb_oom(ldb);
273                                 return NULL;
274                         }
275                         ctrl[i]->oid = LDB_CONTROL_ASQ_OID;
276                         ctrl[i]->critical = crit;
277                         control = talloc(ctrl[i], struct ldb_asq_control);
278                         control->request = 1;
279                         control->source_attribute = talloc_strdup(control, attr);
280                         control->src_attr_len = strlen(attr);
281                         ctrl[i]->data = control;
282
283                         continue;
284                 }
285
286                 if (strncmp(control_strings[i], "extended_dn:", 12) == 0) {
287                         struct ldb_extended_dn_control *control;
288                         const char *p;
289                         int crit, type, ret;
290
291                         p = &(control_strings[i][12]);
292                         ret = sscanf(p, "%d:%d", &crit, &type);
293                         if ((ret != 2) || (crit < 0) || (crit > 1) || (type < 0) || (type > 1)) {
294                                 error_string = talloc_asprintf(mem_ctx, "invalid extended_dn control syntax\n");
295                                 error_string = talloc_asprintf_append(error_string, " syntax: crit(b):type(b)\n");
296                                 error_string = talloc_asprintf_append(error_string, "   note: b = boolean");
297                                 ldb_set_errstring(ldb, error_string);
298                                 talloc_free(error_string);
299                                 return NULL;
300                         }
301
302                         ctrl[i] = talloc(ctrl, struct ldb_control);
303                         if (!ctrl[i]) {
304                                 ldb_oom(ldb);
305                                 return NULL;
306                         }
307                         ctrl[i]->oid = LDB_CONTROL_EXTENDED_DN_OID;
308                         ctrl[i]->critical = crit;
309                         control = talloc(ctrl[i], struct ldb_extended_dn_control);
310                         control->type = type;
311                         ctrl[i]->data = control;
312
313                         continue;
314                 }
315
316                 if (strncmp(control_strings[i], "sd_flags:", 9) == 0) {
317                         struct ldb_sd_flags_control *control;
318                         const char *p;
319                         int crit, ret;
320                         unsigned secinfo_flags;
321
322                         p = &(control_strings[i][9]);
323                         ret = sscanf(p, "%d:%u", &crit, &secinfo_flags);
324                         if ((ret != 2) || (crit < 0) || (crit > 1) || (secinfo_flags < 0) || (secinfo_flags > 0xF)) {
325                                 error_string = talloc_asprintf(mem_ctx, "invalid sd_flags control syntax\n");
326                                 error_string = talloc_asprintf_append(error_string, " syntax: crit(b):secinfo_flags(n)\n");
327                                 error_string = talloc_asprintf_append(error_string, "   note: b = boolean, n = number");
328                                 ldb_set_errstring(ldb, error_string);
329                                 talloc_free(error_string);
330                                 return NULL;
331                         }
332
333                         ctrl[i] = talloc(ctrl, struct ldb_control);
334                         if (!ctrl[i]) {
335                                 ldb_oom(ldb);
336                                 return NULL;
337                         }
338                         ctrl[i]->oid = LDB_CONTROL_SD_FLAGS_OID;
339                         ctrl[i]->critical = crit;
340                         control = talloc(ctrl[i], struct ldb_sd_flags_control);
341                         control->secinfo_flags = secinfo_flags;
342                         ctrl[i]->data = control;
343
344                         continue;
345                 }
346
347                 if (strncmp(control_strings[i], "search_options:", 15) == 0) {
348                         struct ldb_search_options_control *control;
349                         const char *p;
350                         int crit, ret;
351                         unsigned search_options;
352
353                         p = &(control_strings[i][15]);
354                         ret = sscanf(p, "%d:%u", &crit, &search_options);
355                         if ((ret != 2) || (crit < 0) || (crit > 1) || (search_options < 0) || (search_options > 0xF)) {
356                                 error_string = talloc_asprintf(mem_ctx, "invalid search_options control syntax\n");
357                                 error_string = talloc_asprintf_append(error_string, " syntax: crit(b):search_options(n)\n");
358                                 error_string = talloc_asprintf_append(error_string, "   note: b = boolean, n = number");
359                                 ldb_set_errstring(ldb, error_string);
360                                 talloc_free(error_string);
361                                 return NULL;
362                         }
363
364                         ctrl[i] = talloc(ctrl, struct ldb_control);
365                         if (!ctrl[i]) {
366                                 ldb_oom(ldb);
367                                 return NULL;
368                         }
369                         ctrl[i]->oid = LDB_CONTROL_SEARCH_OPTIONS_OID;
370                         ctrl[i]->critical = crit;
371                         control = talloc(ctrl[i], struct ldb_search_options_control);
372                         control->search_options = search_options;
373                         ctrl[i]->data = control;
374
375                         continue;
376                 }
377
378                 if (strncmp(control_strings[i], "domain_scope:", 13) == 0) {
379                         const char *p;
380                         int crit, ret;
381
382                         p = &(control_strings[i][13]);
383                         ret = sscanf(p, "%d", &crit);
384                         if ((ret != 1) || (crit < 0) || (crit > 1)) {
385                                 error_string = talloc_asprintf(mem_ctx, "invalid domain_scope control syntax\n");
386                                 error_string = talloc_asprintf_append(error_string, " syntax: crit(b)\n");
387                                 error_string = talloc_asprintf_append(error_string, "   note: b = boolean");
388                                 ldb_set_errstring(ldb, error_string);
389                                 talloc_free(error_string);
390                                 return NULL;
391                         }
392
393                         ctrl[i] = talloc(ctrl, struct ldb_control);
394                         if (!ctrl[i]) {
395                                 ldb_oom(ldb);
396                                 return NULL;
397                         }
398                         ctrl[i]->oid = LDB_CONTROL_DOMAIN_SCOPE_OID;
399                         ctrl[i]->critical = crit;
400                         ctrl[i]->data = NULL;
401
402                         continue;
403                 }
404
405                 if (strncmp(control_strings[i], "paged_results:", 14) == 0) {
406                         struct ldb_paged_control *control;
407                         const char *p;
408                         int crit, size, ret;
409                        
410                         p = &(control_strings[i][14]);
411                         ret = sscanf(p, "%d:%d", &crit, &size);
412
413                         if ((ret != 2) || (crit < 0) || (crit > 1) || (size < 0)) {
414                                 error_string = talloc_asprintf(mem_ctx, "invalid paged_results control syntax\n");
415                                 error_string = talloc_asprintf_append(error_string, " syntax: crit(b):size(n)\n");
416                                 error_string = talloc_asprintf_append(error_string, "   note: b = boolean, n = number");
417                                 ldb_set_errstring(ldb, error_string);
418                                 talloc_free(error_string);
419                                 return NULL;
420                         }
421
422                         ctrl[i] = talloc(ctrl, struct ldb_control);
423                         if (!ctrl[i]) {
424                                 ldb_oom(ldb);
425                                 return NULL;
426                         }
427                         ctrl[i]->oid = LDB_CONTROL_PAGED_RESULTS_OID;
428                         ctrl[i]->critical = crit;
429                         control = talloc(ctrl[i], struct ldb_paged_control);
430                         control->size = size;
431                         control->cookie = NULL;
432                         control->cookie_len = 0;
433                         ctrl[i]->data = control;
434
435                         continue;
436                 }
437
438                 if (strncmp(control_strings[i], "server_sort:", 12) == 0) {
439                         struct ldb_server_sort_control **control;
440                         const char *p;
441                         char attr[256];
442                         char rule[128];
443                         int crit, rev, ret;
444
445                         attr[0] = '\0';
446                         rule[0] = '\0';
447                         p = &(control_strings[i][12]);
448                         ret = sscanf(p, "%d:%d:%255[^:]:%127[^:]", &crit, &rev, attr, rule);
449                         if ((ret < 3) || (crit < 0) || (crit > 1) || (rev < 0 ) || (rev > 1) ||attr[0] == '\0') {
450                                 error_string = talloc_asprintf(mem_ctx, "invalid server_sort control syntax\n");
451                                 error_string = talloc_asprintf_append(error_string, " syntax: crit(b):rev(b):attr(s)[:rule(s)]\n");
452                                 error_string = talloc_asprintf_append(error_string, "   note: b = boolean, s = string");
453                                 ldb_set_errstring(ldb, error_string);
454                                 talloc_free(error_string);
455                                 return NULL;
456                         }
457                         ctrl[i] = talloc(ctrl, struct ldb_control);
458                         if (!ctrl[i]) {
459                                 ldb_oom(ldb);
460                                 return NULL;
461                         }
462                         ctrl[i]->oid = LDB_CONTROL_SERVER_SORT_OID;
463                         ctrl[i]->critical = crit;
464                         control = talloc_array(ctrl[i], struct ldb_server_sort_control *, 2);
465                         control[0] = talloc(control, struct ldb_server_sort_control);
466                         control[0]->attributeName = talloc_strdup(control, attr);
467                         if (rule[0])
468                                 control[0]->orderingRule = talloc_strdup(control, rule);
469                         else
470                                 control[0]->orderingRule = NULL;
471                         control[0]->reverse = rev;
472                         control[1] = NULL;
473                         ctrl[i]->data = control;
474
475                         continue;
476                 }
477
478                 if (strncmp(control_strings[i], "notification:", 13) == 0) {
479                         const char *p;
480                         int crit, ret;
481
482                         p = &(control_strings[i][13]);
483                         ret = sscanf(p, "%d", &crit);
484                         if ((ret != 1) || (crit < 0) || (crit > 1)) {
485                                 error_string = talloc_asprintf(mem_ctx, "invalid notification control syntax\n");
486                                 error_string = talloc_asprintf_append(error_string, " syntax: crit(b)\n");
487                                 error_string = talloc_asprintf_append(error_string, "   note: b = boolean");
488                                 ldb_set_errstring(ldb, error_string);
489                                 talloc_free(error_string);
490                                 return NULL;
491                         }
492
493                         ctrl[i] = talloc(ctrl, struct ldb_control);
494                         if (!ctrl[i]) {
495                                 ldb_oom(ldb);
496                                 return NULL;
497                         }
498                         ctrl[i]->oid = LDB_CONTROL_NOTIFICATION_OID;
499                         ctrl[i]->critical = crit;
500                         ctrl[i]->data = NULL;
501
502                         continue;
503                 }
504
505                 if (strncmp(control_strings[i], "show_deleted:", 13) == 0) {
506                         const char *p;
507                         int crit, ret;
508
509                         p = &(control_strings[i][13]);
510                         ret = sscanf(p, "%d", &crit);
511                         if ((ret != 1) || (crit < 0) || (crit > 1)) {
512                                 error_string = talloc_asprintf(mem_ctx, "invalid show_deleted control syntax\n");
513                                 error_string = talloc_asprintf_append(error_string, " syntax: crit(b)\n");
514                                 error_string = talloc_asprintf_append(error_string, "   note: b = boolean");
515                                 ldb_set_errstring(ldb, error_string);
516                                 talloc_free(error_string);
517                                 return NULL;
518                         }
519
520                         ctrl[i] = talloc(ctrl, struct ldb_control);
521                         if (!ctrl[i]) {
522                                 ldb_oom(ldb);
523                                 return NULL;
524                         }
525                         ctrl[i]->oid = LDB_CONTROL_SHOW_DELETED_OID;
526                         ctrl[i]->critical = crit;
527                         ctrl[i]->data = NULL;
528
529                         continue;
530                 }
531
532                 if (strncmp(control_strings[i], "permissive_modify:", 18) == 0) {
533                         const char *p;
534                         int crit, ret;
535
536                         p = &(control_strings[i][18]);
537                         ret = sscanf(p, "%d", &crit);
538                         if ((ret != 1) || (crit < 0) || (crit > 1)) {
539                                 error_string = talloc_asprintf(mem_ctx, "invalid permissive_modify control syntax\n");
540                                 error_string = talloc_asprintf_append(error_string, " syntax: crit(b)\n");
541                                 error_string = talloc_asprintf_append(error_string, "   note: b = boolean");
542                                 ldb_set_errstring(ldb, error_string);
543                                 talloc_free(error_string);
544                                 return NULL;
545                         }
546
547                         ctrl[i] = talloc(ctrl, struct ldb_control);
548                         if (!ctrl[i]) {
549                                 ldb_oom(ldb);
550                                 return NULL;
551                         }
552                         ctrl[i]->oid = LDB_CONTROL_PERMISSIVE_MODIFY_OID;
553                         ctrl[i]->critical = crit;
554                         ctrl[i]->data = NULL;
555
556                         continue;
557                 }
558
559                 /* no controls matched, throw an error */
560                 ldb_asprintf_errstring(ldb, "Invalid control name: '%s'", control_strings[i]);
561                 return NULL;
562         }
563
564         ctrl[i] = NULL;
565
566         return ctrl;
567 }
568
569