r9672: Fix build for compilers that don't like undefined-length arrays at the end...
[sfrench/samba-autobuild/.git] / source / lib / ldb / ldb_map / ldb_map.c
1 /* 
2    ldb database library - map backend
3
4    Copyright (C) Jelmer Vernooij 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 2 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, write to the Free Software
22    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23 */
24
25 #include "includes.h"
26 #include "lib/ldb/include/ldb.h"
27 #include "lib/ldb/include/ldb_private.h"
28 #include "lib/ldb/ldb_map/ldb_map.h"
29
30 /* TODO:
31  *  - objectclass hint in ldb_map_attribute 
32  *     for use when multiple remote attributes (independant of each other)
33  *     map to one local attribute. E.g.: (uid, gidNumber) -> unixName
34  */
35
36 struct map_private {
37         const struct ldb_map_attribute *attribute_maps;
38         const struct ldb_map_objectclass *objectclass_maps;
39         const char *last_err_string;
40 };
41
42 /* find an attribute by the local name */
43 static const struct ldb_map_attribute *map_find_attr_local(struct ldb_module *module, const char *attr)
44 {
45         struct map_private *privdat = module->private_data;
46         int i;
47         for (i = 0; privdat->attribute_maps[i].local_name; i++) {
48                 if (!strcmp(privdat->attribute_maps[i].local_name, attr)) 
49                         return &privdat->attribute_maps[i];
50         }
51
52         return NULL;
53 }
54
55 /* find an attribute by the remote name */
56 static const struct ldb_map_attribute *map_find_attr_remote(struct ldb_module *module, const char *attr)
57 {
58         struct map_private *privdat = module->private_data;
59         int i;
60         for (i = 0; privdat->attribute_maps[i].local_name; i++) {
61                 if (privdat->attribute_maps[i].type != MAP_RENAME &&
62                         privdat->attribute_maps[i].type != MAP_CONVERT) 
63                         continue;
64
65                 if (!strcmp(privdat->attribute_maps[i].u.rename.remote_name, attr)) 
66                         return &privdat->attribute_maps[i];
67         }
68
69         return NULL;
70 }
71
72 static struct ldb_parse_tree *ldb_map_parse_tree(struct ldb_module *module, const struct ldb_parse_tree *tree)
73 {
74         int i;
75         const struct ldb_map_attribute *attr;
76         struct ldb_parse_tree *new_tree = talloc_memdup(module, tree, sizeof(*tree));
77
78         /* Find attr in question and:
79          *  - if it has a convert_operator function, run that
80          *  - otherwise, replace attr name with required[0] */
81
82         if (tree->operation == LDB_OP_AND || 
83                 tree->operation == LDB_OP_OR) {
84                 for (i = 0; i < tree->u.list.num_elements; i++) {
85                         new_tree->u.list.elements[i] = ldb_map_parse_tree(module, tree->u.list.elements[i]);
86                 }
87
88                 return new_tree;
89         }
90                 
91         if (tree->operation == LDB_OP_NOT) {
92                 new_tree->u.isnot.child = ldb_map_parse_tree(module, tree->u.isnot.child);
93                 return new_tree;
94         }
95
96         /* tree->operation is LDB_OP_EQUALITY, LDB_OP_SUBSTRING, LDB_OP_GREATER,
97          * LDB_OP_LESS, LDB_OP_APPROX, LDB_OP_PRESENT or LDB_OP_EXTENDED
98          *
99          * (all have attr as the first element)
100          */
101
102         attr = map_find_attr_local(module, tree->u.equality.attr);
103
104         if (!attr) {
105                 DEBUG(0, ("Unable to find local attribute '%s', leaving as is", tree->u.equality.attr));
106                 return new_tree;
107         }
108
109         if (attr->type == MAP_IGNORE)
110                 return NULL;
111
112         if (attr->convert_operator) {
113                 /* Run convert_operator */
114                 talloc_free(new_tree);
115                 new_tree = attr->convert_operator(module, tree);
116         } else {
117                 new_tree->u.equality.attr = talloc_strdup(new_tree, attr->u.rename.remote_name);
118         }
119
120         return new_tree;
121 }
122
123 /* Remote DN -> Local DN */
124 static struct ldb_dn *map_remote_dn(struct ldb_module *module, const struct ldb_dn *dn)
125 {
126         struct ldb_dn *newdn;
127         int i;
128
129         newdn = talloc_memdup(module, dn, sizeof(*dn));
130         if (!newdn) 
131                 return NULL;
132
133         newdn->components = talloc_memdup(newdn, dn->components, sizeof(struct ldb_dn_component) * newdn->comp_num); 
134
135         if (!newdn->components)
136                 return NULL;
137
138         /* For each rdn, map the attribute name and possibly the 
139          * complete rdn */
140         
141         for (i = 0; i < dn->comp_num; i++) {
142                 const struct ldb_map_attribute *attr = map_find_attr_remote(module, dn->components[i].name);
143
144                 /* Unknown attribute - leave this dn as is and hope the best... */
145                 if (!attr)
146                         continue;
147
148                 if (attr->type == MAP_IGNORE) {
149                         DEBUG(0, ("Local MAP_IGNORE attribute '%s' used in DN!", dn->components[i].name));
150                         talloc_free(newdn);
151                         return NULL;
152                 }
153
154                 if (attr->type == MAP_GENERATE) {
155                         DEBUG(0, ("Local MAP_GENERATE attribute '%s' used in DN!", dn->components[i].name));
156                         talloc_free(newdn);
157
158                         return NULL;
159                 }
160
161                 if (attr->type == MAP_CONVERT) {
162                         struct ldb_message_element elm, *newelm;
163                         struct ldb_val vals[1] = { dn->components[i].value };
164                         elm.flags = 0;
165                         elm.name = attr->u.convert.remote_name;
166                         elm.num_values = 1;
167                         elm.values = vals;
168
169                         newelm = attr->u.convert.convert_remote(module, attr->local_name, &elm);
170
171                         newdn->components[i].name = talloc_strdup(module, newelm->name);
172                         newdn->components[i].value = newelm->values[0];
173                 } else if (attr->type == MAP_RENAME) {
174                         newdn->components[i].name = talloc_strdup(module, attr->local_name);
175                 }
176         }
177         return newdn;
178 }
179
180 /* Local DN -> Remote DN */
181 static struct ldb_dn *map_local_dn(struct ldb_module *module, const struct ldb_dn *dn)
182 {       struct ldb_dn *newdn;
183         int i;
184         struct ldb_parse_tree eqtree, *new_eqtree;
185
186         newdn = talloc_memdup(module, dn, sizeof(*dn));
187         if (!newdn) 
188                 return NULL;
189
190         newdn->components = talloc_memdup(newdn, dn->components, sizeof(struct ldb_dn_component) * newdn->comp_num); 
191
192         if (!newdn->components)
193                 return NULL;
194
195         /* For each rdn, map the attribute name and possibly the 
196          * complete rdn using an equality convert_operator call */
197         
198         for (i = 0; i < dn->comp_num; i++) {
199                 const struct ldb_map_attribute *attr = map_find_attr_local(module, dn->components[i].name);
200
201                 /* Unknown attribute - leave this dn as is and hope the best... */
202                 if (!attr)
203                         continue;
204
205                 if (attr->type == MAP_IGNORE) {
206                         DEBUG(0, ("Local MAP_IGNORE attribute '%s' used in DN!", dn->components[i].name));
207                         talloc_free(newdn);
208                         return NULL;
209                 }
210
211                 if (attr->type == MAP_GENERATE) {
212                         DEBUG(0, ("Local MAP_GENERATE attribute '%s' used in DN!", dn->components[i].name));
213                         talloc_free(newdn);
214
215                         return NULL;
216                 }
217
218                 /* Simple rename/convert only */
219                 if (attr->convert_operator) {
220                         /* Fancy stuff */
221                         eqtree.operation = LDB_OP_EQUALITY;
222                         eqtree.u.equality.attr = dn->components[i].name;
223                         eqtree.u.equality.value = dn->components[i].value;
224
225                         new_eqtree = ldb_map_parse_tree(module, &eqtree);
226
227                         /* Silently continue for now */
228                         if (!new_eqtree) {
229                                 DEBUG(0, ("Unable to convert RDN for attribute %s\n", dn->components[i].name));
230                                 continue;
231                         }
232
233                         newdn->components[i].name = new_eqtree->u.equality.attr;
234                         newdn->components[i].value = new_eqtree->u.equality.value;
235                 } else if (attr->type == MAP_CONVERT) {
236                         struct ldb_message_element elm, *newelm;
237                         struct ldb_val vals[1] = { dn->components[i].value };
238                         elm.flags = 0;
239                         elm.name = attr->local_name;
240                         elm.num_values = 1;
241                         elm.values = vals;
242
243                         newelm = attr->u.convert.convert_local(module, attr->u.convert.remote_name, &elm);
244
245                         newdn->components[i].name = talloc_strdup(module, newelm->name);
246                         newdn->components[i].value = newelm->values[0];
247                 } else if (attr->type == MAP_RENAME) {
248                         newdn->components[i].name = talloc_strdup(module, attr->u.rename.remote_name);
249                 }
250         }
251
252         return newdn;
253 }
254
255
256
257 /* Loop over ldb_map_attribute array and add remote_names */
258 static const char **ldb_map_attrs(struct ldb_module *module, const char *const attrs[])
259 {
260         int i;
261         const char **ret;
262         int ar_size = 0, last_element = 0;
263
264         /* Start with good guess of number of elements */
265         for (i = 0; attrs[i]; i++);
266
267         ret = talloc_array(module, const char *, i);
268         ar_size = i;
269
270         for (i = 0; attrs[i]; i++) {
271                 int j;
272                 const struct ldb_map_attribute *attr = map_find_attr_local(module, attrs[i]);
273
274                 if (!attr) {
275                         DEBUG(0, ("Local attribute '%s' does not have a definition!\n", attrs[i]));
276                         continue;
277                 }
278
279                 switch (attr->type)
280                 { 
281                         case MAP_IGNORE: break;
282                         case MAP_KEEP: 
283                                 if (last_element >= ar_size) {
284                                         ret = talloc_realloc(module, ret, const char *, ar_size+1);
285                                         ar_size++;
286                                 }
287                                 ret[last_element] = attr->local_name;
288                                 last_element++;
289                                 break;
290
291                         case MAP_RENAME:
292                         case MAP_CONVERT:
293                                 if (last_element >= ar_size) {
294                                         ret = talloc_realloc(module, ret, const char *, ar_size+1);
295                                         ar_size++;
296                                 }
297                                 ret[last_element] = attr->u.rename.remote_name;
298                                 last_element++;
299                                 break;
300
301                         case MAP_GENERATE:
302                                 /* Add remote_names[] for this attribute to the list of 
303                                  * attributes to request from the remote server */
304                                 for (j = 0; attr->u.generate.remote_names[j]; j++) {
305                                         if (last_element >= ar_size) {
306                                                 ret = talloc_realloc(module, ret, const char *, ar_size+1);
307                                                 ar_size++;
308                                         }
309                                         ret[last_element] = attr->u.generate.remote_names[j];                   
310                                         last_element++;
311                                 }
312                                 break;
313                 } 
314         }
315
316         return NULL;
317 }
318
319 static struct ldb_message *ldb_map_message_incoming(struct ldb_module *module, const char * const*attrs, const struct ldb_message *mi)
320 {
321         int i;
322         struct ldb_message *msg = talloc_zero(module, struct ldb_message);
323         struct ldb_message_element *elm, *oldelm;
324
325         msg->dn = map_remote_dn(module, mi->dn);
326
327         /* Loop over attrs, find in ldb_map_attribute array and 
328          * run generate() */
329
330         for (i = 0; attrs[i]; i++) {
331                 const struct ldb_map_attribute *attr = map_find_attr_local(module, attrs[i]);
332
333                 if (!attr) {
334                         DEBUG(0, ("Unable to find local attribute '%s' when generating incoming message", attrs[i]));
335                         continue;
336                 }
337
338                 switch (attr->type) {
339                         case MAP_IGNORE:break;
340                         case MAP_RENAME:
341                                 oldelm = ldb_msg_find_element(mi, attr->u.rename.remote_name);
342                                 elm = talloc_memdup(msg, oldelm, sizeof(*oldelm));
343                                 elm->name = talloc_strdup(elm, attr->local_name);
344
345                                 ldb_msg_add(module->ldb, msg, elm, 0);
346                                 break;
347                                 
348                         case MAP_CONVERT:
349                                 oldelm = ldb_msg_find_element(mi, attr->u.rename.remote_name);
350                                 elm = attr->u.convert.convert_local(msg, attr->local_name, oldelm);
351
352                                 ldb_msg_add(module->ldb, msg, elm, 0);
353                                 break;
354
355                         case MAP_KEEP:
356                                 ldb_msg_add(module->ldb, msg, ldb_msg_find_element(mi, attr->local_name), 0);
357                                 break;
358
359                         case MAP_GENERATE:
360                                 elm = attr->u.generate.generate_local(msg, attr->local_name, mi);
361                                 ldb_msg_add(module->ldb, msg, elm, 0);
362                                 break;
363                         default: 
364                                 DEBUG(0, ("Unknown attr->type for %s", attr->local_name));
365                                 break;
366                 }
367         }
368
369         return msg;
370 }
371
372 static struct ldb_message *ldb_map_message_outgoing(struct ldb_module *module, const struct ldb_message *mo)
373 {
374         struct ldb_message *msg = talloc_zero(module, struct ldb_message);
375         struct ldb_message_element *elm;
376         int i;
377         
378         msg->private_data = mo->private_data;
379         
380         msg->dn = map_local_dn(module, mo->dn);
381
382         /* Loop over mi and call generate_remote for each attribute */
383         for (i = 0; i < mo->num_elements; i++) {
384                 const struct ldb_map_attribute *attr = map_find_attr_local(module, mo->elements[i].name);
385
386                 if (!attr) {
387                         DEBUG(0, ("Undefined local attribute '%s', ignoring\n", mo->elements[i].name));
388                         continue;
389                 }
390
391                 switch (attr->type) {
392                 case MAP_IGNORE: break;
393                 case MAP_RENAME:
394                         elm = talloc_memdup(msg, &msg->elements[i], sizeof(*elm));
395                         elm->name = talloc_strdup(elm, attr->u.rename.remote_name);
396
397                         ldb_msg_add(module->ldb, msg, elm, 0);
398                         break;
399
400                 case MAP_CONVERT:
401                         elm = attr->u.convert.convert_remote(msg, attr->local_name, &msg->elements[i]);
402                         ldb_msg_add(module->ldb, msg, elm, 0);
403                         break;
404
405                 case MAP_KEEP:
406                         ldb_msg_add(module->ldb, msg, &msg->elements[i], 0);    
407                         break;
408
409                 case MAP_GENERATE:
410                         attr->u.generate.generate_remote(attr->local_name, mo, msg);
411                         break;
412                 } 
413         }
414
415         return msg;
416 }
417
418 /*
419   rename a record
420 */
421 static int map_rename(struct ldb_module *module, const struct ldb_dn *olddn, const struct ldb_dn *newdn)
422 {
423         struct ldb_dn *n_olddn, *n_newdn;
424         int ret;
425         
426         n_olddn = map_local_dn(module, olddn);
427         n_newdn = map_local_dn(module, newdn);
428
429         ret = ldb_next_rename_record(module, n_olddn, n_newdn);
430
431         talloc_free(n_olddn);
432         talloc_free(n_newdn);
433         
434         return ret;
435 }
436
437 /*
438   delete a record
439 */
440 static int map_delete(struct ldb_module *module, const struct ldb_dn *dn)
441 {
442         struct ldb_dn *newdn;
443         int ret;
444
445         newdn = map_local_dn(module, dn);
446
447         ret = ldb_next_delete_record(module, newdn);
448
449         talloc_free(newdn);
450
451         return ret;
452 }
453
454 /*
455   search for matching records using a ldb_parse_tree
456 */
457 static int map_search_bytree(struct ldb_module *module, const struct ldb_dn *base,
458                               enum ldb_scope scope, struct ldb_parse_tree *tree,
459                               const char * const *attrs, struct ldb_message ***res)
460 {
461         int ret;
462         const char **newattrs;
463         struct ldb_parse_tree *new_tree;
464         struct ldb_dn *new_base;
465         struct ldb_message **newres;
466         int i;
467
468         new_tree = ldb_map_parse_tree(module, tree);
469         newattrs = ldb_map_attrs(module, attrs); 
470         new_base = map_local_dn(module, base);
471
472         ret = ldb_next_search_bytree(module, new_base, scope, new_tree, newattrs, &newres);
473
474         talloc_free(new_base);
475         talloc_free(new_tree);
476         talloc_free(newattrs);
477
478         for (i = 0; i < ret; i++) {
479                 *res[i] = ldb_map_message_incoming(module, attrs, newres[i]);
480                 talloc_free(newres[i]);
481         }
482
483         return ret;
484 }
485 /*
486   search for matching records
487 */
488 static int map_search(struct ldb_module *module, const struct ldb_dn *base,
489                        enum ldb_scope scope, const char *expression,
490                        const char * const *attrs, struct ldb_message ***res)
491 {
492         struct map_private *map = module->private_data;
493         struct ldb_parse_tree *tree;
494         int ret;
495
496         tree = ldb_parse_tree(map, expression);
497         if (tree == NULL) {
498                 map->last_err_string = "expression parse failed";
499                 return -1;
500         }
501
502         ret = map_search_bytree(module, base, scope, tree, attrs, res);
503         talloc_free(tree);
504         return ret;
505 }
506
507 /*
508   add a record
509 */
510 static int map_add(struct ldb_module *module, const struct ldb_message *msg)
511 {
512         struct ldb_message *nmsg = ldb_map_message_outgoing(module, msg);
513         int ret;
514
515         ret = ldb_next_add_record(module, nmsg);
516
517         talloc_free(nmsg);
518
519         return ret;
520 }
521
522
523
524
525 /*
526   modify a record
527 */
528 static int map_modify(struct ldb_module *module, const struct ldb_message *msg)
529 {
530         struct ldb_message *nmsg = ldb_map_message_outgoing(module, msg);
531         int ret;
532
533         ret = ldb_next_modify_record(module, nmsg);
534
535         talloc_free(nmsg);
536
537         return ret;
538 }
539
540 static int map_lock(struct ldb_module *module, const char *lockname)
541 {
542         return ldb_next_named_lock(module, lockname);
543 }
544
545 static int map_unlock(struct ldb_module *module, const char *lockname)
546 {
547         return ldb_next_named_unlock(module, lockname);
548 }
549
550 /*
551   return extended error information
552 */
553 static const char *map_errstring(struct ldb_module *module)
554 {
555         struct map_private *map = module->private_data;
556         
557         if (map->last_err_string)
558                 return map->last_err_string;
559
560         return ldb_next_errstring(module);
561 }
562
563 static const struct ldb_module_ops map_ops = {
564         .name          = "map",
565         .search        = map_search,
566         .search_bytree = map_search_bytree,
567         .add_record    = map_add,
568         .modify_record = map_modify,
569         .delete_record = map_delete,
570         .rename_record = map_rename,
571         .named_lock    = map_lock,
572         .named_unlock  = map_unlock,
573         .errstring     = map_errstring
574 };
575
576 /* the init function */
577 struct ldb_module *ldb_map_init(struct ldb_context *ldb, const struct ldb_map_attribute *attrs, const struct ldb_map_objectclass *ocls, const char *options[])
578 {
579         struct ldb_module *ctx;
580         struct map_private *data;
581
582         ctx = talloc(ldb, struct ldb_module);
583         if (!ctx)
584                 return NULL;
585
586         data = talloc(ctx, struct map_private);
587         if (!data) {
588                 talloc_free(ctx);
589                 return NULL;
590         }
591
592         data->attribute_maps = attrs;
593         data->objectclass_maps = ocls;
594         ctx->private_data = data;
595         ctx->ldb = ldb;
596         ctx->prev = ctx->next = NULL;
597         ctx->ops = &map_ops;
598
599         return ctx;
600 }