r26192: Handle, test and implement the style of extended_dn requiest that MMC uses.
[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                                 ret = sscanf(p, "%d", &crit);
295                                 if ((ret != 1) || (crit < 0) || (crit > 1)) {
296                                         error_string = talloc_asprintf(mem_ctx, "invalid extended_dn control syntax\n");
297                                         error_string = talloc_asprintf_append(error_string, " syntax: crit(b)[:type(i)]\n");
298                                         error_string = talloc_asprintf_append(error_string, "   note: b = boolean\n");
299                                         error_string = talloc_asprintf_append(error_string, "         i = integer\n");
300                                         error_string = talloc_asprintf_append(error_string, "   valid values are: 0 - hexadecimal representation\n");
301                                         error_string = talloc_asprintf_append(error_string, "                     1 - normal string representation");
302                                         ldb_set_errstring(ldb, error_string);
303                                         talloc_free(error_string);
304                                         return NULL;
305                                 }
306                                 control = NULL;
307                         } else {
308                                 control = talloc(ctrl, struct ldb_extended_dn_control);
309                                 control->type = type;
310                         }
311
312                         ctrl[i] = talloc(ctrl, struct ldb_control);
313                         if (!ctrl[i]) {
314                                 ldb_oom(ldb);
315                                 return NULL;
316                         }
317                         ctrl[i]->oid = LDB_CONTROL_EXTENDED_DN_OID;
318                         ctrl[i]->critical = crit;
319                         ctrl[i]->data = talloc_steal(ctrl[i], control);
320
321                         continue;
322                 }
323
324                 if (strncmp(control_strings[i], "sd_flags:", 9) == 0) {
325                         struct ldb_sd_flags_control *control;
326                         const char *p;
327                         int crit, ret;
328                         unsigned secinfo_flags;
329
330                         p = &(control_strings[i][9]);
331                         ret = sscanf(p, "%d:%u", &crit, &secinfo_flags);
332                         if ((ret != 2) || (crit < 0) || (crit > 1) || (secinfo_flags < 0) || (secinfo_flags > 0xF)) {
333                                 error_string = talloc_asprintf(mem_ctx, "invalid sd_flags control syntax\n");
334                                 error_string = talloc_asprintf_append(error_string, " syntax: crit(b):secinfo_flags(n)\n");
335                                 error_string = talloc_asprintf_append(error_string, "   note: b = boolean, n = number");
336                                 ldb_set_errstring(ldb, error_string);
337                                 talloc_free(error_string);
338                                 return NULL;
339                         }
340
341                         ctrl[i] = talloc(ctrl, struct ldb_control);
342                         if (!ctrl[i]) {
343                                 ldb_oom(ldb);
344                                 return NULL;
345                         }
346                         ctrl[i]->oid = LDB_CONTROL_SD_FLAGS_OID;
347                         ctrl[i]->critical = crit;
348                         control = talloc(ctrl[i], struct ldb_sd_flags_control);
349                         control->secinfo_flags = secinfo_flags;
350                         ctrl[i]->data = control;
351
352                         continue;
353                 }
354
355                 if (strncmp(control_strings[i], "search_options:", 15) == 0) {
356                         struct ldb_search_options_control *control;
357                         const char *p;
358                         int crit, ret;
359                         unsigned search_options;
360
361                         p = &(control_strings[i][15]);
362                         ret = sscanf(p, "%d:%u", &crit, &search_options);
363                         if ((ret != 2) || (crit < 0) || (crit > 1) || (search_options < 0) || (search_options > 0xF)) {
364                                 error_string = talloc_asprintf(mem_ctx, "invalid search_options control syntax\n");
365                                 error_string = talloc_asprintf_append(error_string, " syntax: crit(b):search_options(n)\n");
366                                 error_string = talloc_asprintf_append(error_string, "   note: b = boolean, n = number");
367                                 ldb_set_errstring(ldb, error_string);
368                                 talloc_free(error_string);
369                                 return NULL;
370                         }
371
372                         ctrl[i] = talloc(ctrl, struct ldb_control);
373                         if (!ctrl[i]) {
374                                 ldb_oom(ldb);
375                                 return NULL;
376                         }
377                         ctrl[i]->oid = LDB_CONTROL_SEARCH_OPTIONS_OID;
378                         ctrl[i]->critical = crit;
379                         control = talloc(ctrl[i], struct ldb_search_options_control);
380                         control->search_options = search_options;
381                         ctrl[i]->data = control;
382
383                         continue;
384                 }
385
386                 if (strncmp(control_strings[i], "domain_scope:", 13) == 0) {
387                         const char *p;
388                         int crit, ret;
389
390                         p = &(control_strings[i][13]);
391                         ret = sscanf(p, "%d", &crit);
392                         if ((ret != 1) || (crit < 0) || (crit > 1)) {
393                                 error_string = talloc_asprintf(mem_ctx, "invalid domain_scope control syntax\n");
394                                 error_string = talloc_asprintf_append(error_string, " syntax: crit(b)\n");
395                                 error_string = talloc_asprintf_append(error_string, "   note: b = boolean");
396                                 ldb_set_errstring(ldb, error_string);
397                                 talloc_free(error_string);
398                                 return NULL;
399                         }
400
401                         ctrl[i] = talloc(ctrl, struct ldb_control);
402                         if (!ctrl[i]) {
403                                 ldb_oom(ldb);
404                                 return NULL;
405                         }
406                         ctrl[i]->oid = LDB_CONTROL_DOMAIN_SCOPE_OID;
407                         ctrl[i]->critical = crit;
408                         ctrl[i]->data = NULL;
409
410                         continue;
411                 }
412
413                 if (strncmp(control_strings[i], "paged_results:", 14) == 0) {
414                         struct ldb_paged_control *control;
415                         const char *p;
416                         int crit, size, ret;
417                        
418                         p = &(control_strings[i][14]);
419                         ret = sscanf(p, "%d:%d", &crit, &size);
420
421                         if ((ret != 2) || (crit < 0) || (crit > 1) || (size < 0)) {
422                                 error_string = talloc_asprintf(mem_ctx, "invalid paged_results control syntax\n");
423                                 error_string = talloc_asprintf_append(error_string, " syntax: crit(b):size(n)\n");
424                                 error_string = talloc_asprintf_append(error_string, "   note: b = boolean, n = number");
425                                 ldb_set_errstring(ldb, error_string);
426                                 talloc_free(error_string);
427                                 return NULL;
428                         }
429
430                         ctrl[i] = talloc(ctrl, struct ldb_control);
431                         if (!ctrl[i]) {
432                                 ldb_oom(ldb);
433                                 return NULL;
434                         }
435                         ctrl[i]->oid = LDB_CONTROL_PAGED_RESULTS_OID;
436                         ctrl[i]->critical = crit;
437                         control = talloc(ctrl[i], struct ldb_paged_control);
438                         control->size = size;
439                         control->cookie = NULL;
440                         control->cookie_len = 0;
441                         ctrl[i]->data = control;
442
443                         continue;
444                 }
445
446                 if (strncmp(control_strings[i], "server_sort:", 12) == 0) {
447                         struct ldb_server_sort_control **control;
448                         const char *p;
449                         char attr[256];
450                         char rule[128];
451                         int crit, rev, ret;
452
453                         attr[0] = '\0';
454                         rule[0] = '\0';
455                         p = &(control_strings[i][12]);
456                         ret = sscanf(p, "%d:%d:%255[^:]:%127[^:]", &crit, &rev, attr, rule);
457                         if ((ret < 3) || (crit < 0) || (crit > 1) || (rev < 0 ) || (rev > 1) ||attr[0] == '\0') {
458                                 error_string = talloc_asprintf(mem_ctx, "invalid server_sort control syntax\n");
459                                 error_string = talloc_asprintf_append(error_string, " syntax: crit(b):rev(b):attr(s)[:rule(s)]\n");
460                                 error_string = talloc_asprintf_append(error_string, "   note: b = boolean, s = string");
461                                 ldb_set_errstring(ldb, error_string);
462                                 talloc_free(error_string);
463                                 return NULL;
464                         }
465                         ctrl[i] = talloc(ctrl, struct ldb_control);
466                         if (!ctrl[i]) {
467                                 ldb_oom(ldb);
468                                 return NULL;
469                         }
470                         ctrl[i]->oid = LDB_CONTROL_SERVER_SORT_OID;
471                         ctrl[i]->critical = crit;
472                         control = talloc_array(ctrl[i], struct ldb_server_sort_control *, 2);
473                         control[0] = talloc(control, struct ldb_server_sort_control);
474                         control[0]->attributeName = talloc_strdup(control, attr);
475                         if (rule[0])
476                                 control[0]->orderingRule = talloc_strdup(control, rule);
477                         else
478                                 control[0]->orderingRule = NULL;
479                         control[0]->reverse = rev;
480                         control[1] = NULL;
481                         ctrl[i]->data = control;
482
483                         continue;
484                 }
485
486                 if (strncmp(control_strings[i], "notification:", 13) == 0) {
487                         const char *p;
488                         int crit, ret;
489
490                         p = &(control_strings[i][13]);
491                         ret = sscanf(p, "%d", &crit);
492                         if ((ret != 1) || (crit < 0) || (crit > 1)) {
493                                 error_string = talloc_asprintf(mem_ctx, "invalid notification control syntax\n");
494                                 error_string = talloc_asprintf_append(error_string, " syntax: crit(b)\n");
495                                 error_string = talloc_asprintf_append(error_string, "   note: b = boolean");
496                                 ldb_set_errstring(ldb, error_string);
497                                 talloc_free(error_string);
498                                 return NULL;
499                         }
500
501                         ctrl[i] = talloc(ctrl, struct ldb_control);
502                         if (!ctrl[i]) {
503                                 ldb_oom(ldb);
504                                 return NULL;
505                         }
506                         ctrl[i]->oid = LDB_CONTROL_NOTIFICATION_OID;
507                         ctrl[i]->critical = crit;
508                         ctrl[i]->data = NULL;
509
510                         continue;
511                 }
512
513                 if (strncmp(control_strings[i], "show_deleted:", 13) == 0) {
514                         const char *p;
515                         int crit, ret;
516
517                         p = &(control_strings[i][13]);
518                         ret = sscanf(p, "%d", &crit);
519                         if ((ret != 1) || (crit < 0) || (crit > 1)) {
520                                 error_string = talloc_asprintf(mem_ctx, "invalid show_deleted control syntax\n");
521                                 error_string = talloc_asprintf_append(error_string, " syntax: crit(b)\n");
522                                 error_string = talloc_asprintf_append(error_string, "   note: b = boolean");
523                                 ldb_set_errstring(ldb, error_string);
524                                 talloc_free(error_string);
525                                 return NULL;
526                         }
527
528                         ctrl[i] = talloc(ctrl, struct ldb_control);
529                         if (!ctrl[i]) {
530                                 ldb_oom(ldb);
531                                 return NULL;
532                         }
533                         ctrl[i]->oid = LDB_CONTROL_SHOW_DELETED_OID;
534                         ctrl[i]->critical = crit;
535                         ctrl[i]->data = NULL;
536
537                         continue;
538                 }
539
540                 if (strncmp(control_strings[i], "permissive_modify:", 18) == 0) {
541                         const char *p;
542                         int crit, ret;
543
544                         p = &(control_strings[i][18]);
545                         ret = sscanf(p, "%d", &crit);
546                         if ((ret != 1) || (crit < 0) || (crit > 1)) {
547                                 error_string = talloc_asprintf(mem_ctx, "invalid permissive_modify control syntax\n");
548                                 error_string = talloc_asprintf_append(error_string, " syntax: crit(b)\n");
549                                 error_string = talloc_asprintf_append(error_string, "   note: b = boolean");
550                                 ldb_set_errstring(ldb, error_string);
551                                 talloc_free(error_string);
552                                 return NULL;
553                         }
554
555                         ctrl[i] = talloc(ctrl, struct ldb_control);
556                         if (!ctrl[i]) {
557                                 ldb_oom(ldb);
558                                 return NULL;
559                         }
560                         ctrl[i]->oid = LDB_CONTROL_PERMISSIVE_MODIFY_OID;
561                         ctrl[i]->critical = crit;
562                         ctrl[i]->data = NULL;
563
564                         continue;
565                 }
566
567                 /* no controls matched, throw an error */
568                 ldb_asprintf_errstring(ldb, "Invalid control name: '%s'", control_strings[i]);
569                 return NULL;
570         }
571
572         ctrl[i] = NULL;
573
574         return ctrl;
575 }
576
577