Fix all other modules to use ldb_module.h instead of ldb_private.h
[kai/samba-autobuild/.git] / source4 / dsdb / samdb / ldb_modules / simple_ldap_map.c
1 /* 
2    ldb database module
3
4    LDAP semantics mapping module
5
6    Copyright (C) Jelmer Vernooij 2005
7    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 /* 
24    This module relies on ldb_map to do all the real work, but performs
25    some of the trivial mappings between AD semantics and that provided
26    by OpenLDAP and similar servers.
27 */
28
29 #include "includes.h"
30 #include "ldb/include/ldb_module.h"
31 #include "ldb/ldb_map/ldb_map.h"
32
33 #include "librpc/gen_ndr/ndr_misc.h"
34 #include "librpc/ndr/libndr.h"
35 #include "dsdb/samdb/samdb.h"
36
37 struct entryuuid_private {
38         struct ldb_context *ldb;
39         struct ldb_dn **base_dns;
40 };
41
42 static struct ldb_val encode_guid(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
43 {
44         struct GUID guid;
45         NTSTATUS status = GUID_from_data_blob(val, &guid);
46         enum ndr_err_code ndr_err;
47         struct ldb_val out = data_blob(NULL, 0);
48
49         if (!NT_STATUS_IS_OK(status)) {
50                 return out;
51         }
52         ndr_err = ndr_push_struct_blob(&out, ctx, NULL, &guid,
53                                        (ndr_push_flags_fn_t)ndr_push_GUID);
54         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
55                 return out;
56         }
57
58         return out;
59 }
60
61 static struct ldb_val guid_always_string(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
62 {
63         struct ldb_val out = data_blob(NULL, 0);
64         struct GUID guid;
65         NTSTATUS status = GUID_from_data_blob(val, &guid);
66         if (!NT_STATUS_IS_OK(status)) {
67                 return out;
68         }
69         return data_blob_string_const(GUID_string(ctx, &guid));
70 }
71
72 static struct ldb_val encode_ns_guid(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
73 {
74         struct GUID guid;
75         NTSTATUS status = NS_GUID_from_string((char *)val->data, &guid);
76         enum ndr_err_code ndr_err;
77         struct ldb_val out = data_blob(NULL, 0);
78
79         if (!NT_STATUS_IS_OK(status)) {
80                 return out;
81         }
82         ndr_err = ndr_push_struct_blob(&out, ctx, NULL, &guid,
83                                        (ndr_push_flags_fn_t)ndr_push_GUID);
84         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
85                 return out;
86         }
87
88         return out;
89 }
90
91 static struct ldb_val guid_ns_string(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
92 {
93         struct ldb_val out = data_blob(NULL, 0);
94         struct GUID guid;
95         NTSTATUS status = GUID_from_data_blob(val, &guid);
96         if (!NT_STATUS_IS_OK(status)) {
97                 return out;
98         }
99         return data_blob_string_const(NS_GUID_string(ctx, &guid));
100 }
101
102 /* The backend holds binary sids, so just copy them back */
103 static struct ldb_val val_copy(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
104 {
105         struct ldb_val out = data_blob(NULL, 0);
106         out = ldb_val_dup(ctx, val);
107
108         return out;
109 }
110
111 /* Ensure we always convert sids into binary, so the backend doesn't have to know about both forms */
112 static struct ldb_val sid_always_binary(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
113 {
114         struct ldb_context *ldb = ldb_module_get_ctx(module);
115         struct ldb_val out = data_blob(NULL, 0);
116         const struct ldb_schema_attribute *a = ldb_schema_attribute_by_name(ldb, "objectSid");
117
118         if (a->syntax->canonicalise_fn(ldb, ctx, val, &out) != LDB_SUCCESS) {
119                 return data_blob(NULL, 0);
120         }
121
122         return out;
123 }
124
125 /* Ensure we always convert objectCategory into a DN */
126 static struct ldb_val objectCategory_always_dn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
127 {
128         struct ldb_context *ldb = ldb_module_get_ctx(module);
129         struct ldb_dn *dn;
130         struct ldb_val out = data_blob(NULL, 0);
131         const struct ldb_schema_attribute *a = ldb_schema_attribute_by_name(ldb, "objectCategory");
132
133         dn = ldb_dn_from_ldb_val(ctx, ldb, val);
134         if (dn && ldb_dn_validate(dn)) {
135                 talloc_free(dn);
136                 return val_copy(module, ctx, val);
137         }
138         talloc_free(dn);
139
140         if (a->syntax->canonicalise_fn(ldb, ctx, val, &out) != LDB_SUCCESS) {
141                 return data_blob(NULL, 0);
142         }
143
144         return out;
145 }
146
147 static struct ldb_val normalise_to_signed32(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
148 {
149         long long int signed_ll = strtoll((const char *)val->data, NULL, 10);
150         if (signed_ll >= 0x80000000LL) {
151                 union {
152                         int32_t signed_int;
153                         uint32_t unsigned_int;
154                 } u = {
155                         .unsigned_int = strtoul((const char *)val->data, NULL, 10)
156                 };
157
158                 struct ldb_val out = data_blob_string_const(talloc_asprintf(ctx, "%d", u.signed_int));
159                 return out;
160         }
161         return val_copy(module, ctx, val);
162 }
163
164 static struct ldb_val usn_to_entryCSN(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
165 {
166         struct ldb_val out;
167         unsigned long long usn = strtoull((const char *)val->data, NULL, 10);
168         time_t t = (usn >> 24);
169         out = data_blob_string_const(talloc_asprintf(ctx, "%s#%06x#00#000000", ldb_timestring(ctx, t), (unsigned int)(usn & 0xFFFFFF)));
170         return out;
171 }
172
173 static unsigned long long entryCSN_to_usn_int(TALLOC_CTX *ctx, const struct ldb_val *val) 
174 {
175         char *entryCSN = talloc_strdup(ctx, (const char *)val->data);
176         char *mod_per_sec;
177         time_t t;
178         unsigned long long usn;
179         char *p;
180         if (!entryCSN) {
181                 return 0;
182         }
183         p = strchr(entryCSN, '#');
184         if (!p) {
185                 return 0;
186         }
187         p[0] = '\0';
188         p++;
189         mod_per_sec = p;
190
191         p = strchr(p, '#');
192         if (!p) {
193                 return 0;
194         }
195         p[0] = '\0';
196         p++;
197
198         usn = strtol(mod_per_sec, NULL, 16);
199
200         t = ldb_string_to_time(entryCSN);
201         
202         usn = usn | ((unsigned long long)t <<24);
203         return usn;
204 }
205
206 static struct ldb_val entryCSN_to_usn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
207 {
208         struct ldb_val out;
209         unsigned long long usn = entryCSN_to_usn_int(ctx, val);
210         out = data_blob_string_const(talloc_asprintf(ctx, "%lld", usn));
211         return out;
212 }
213
214 static struct ldb_val usn_to_timestamp(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
215 {
216         struct ldb_val out;
217         unsigned long long usn = strtoull((const char *)val->data, NULL, 10);
218         time_t t = (usn >> 24);
219         out = data_blob_string_const(ldb_timestring(ctx, t));
220         return out;
221 }
222
223 static struct ldb_val timestamp_to_usn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
224 {
225         struct ldb_val out;
226         time_t t;
227         unsigned long long usn;
228
229         t = ldb_string_to_time((const char *)val->data);
230         
231         usn = ((unsigned long long)t <<24);
232
233         out = data_blob_string_const(talloc_asprintf(ctx, "%lld", usn));
234         return out;
235 }
236
237
238 static const struct ldb_map_attribute entryuuid_attributes[] = 
239 {
240         /* objectGUID */
241         {
242                 .local_name = "objectGUID",
243                 .type = MAP_CONVERT,
244                 .u = {
245                         .convert = {
246                                 .remote_name = "entryUUID", 
247                                 .convert_local = guid_always_string,
248                                 .convert_remote = encode_guid,
249                         },
250                 },
251         },
252         /* invocationId */
253         {
254                 .local_name = "invocationId",
255                 .type = MAP_CONVERT,
256                 .u = {
257                         .convert = {
258                                 .remote_name = "invocationId", 
259                                 .convert_local = guid_always_string,
260                                 .convert_remote = encode_guid,
261                         },
262                 },
263         },
264         /* objectSid */
265         {
266                 .local_name = "objectSid",
267                 .type = MAP_CONVERT,
268                 .u = {
269                         .convert = {
270                                 .remote_name = "objectSid", 
271                                 .convert_local = sid_always_binary,
272                                 .convert_remote = val_copy,
273                         },
274                 },
275         },
276         {
277                 .local_name = "name",
278                 .type = MAP_RENAME,
279                 .u = {
280                         .rename = {
281                                  .remote_name = "samba4RDN"
282                          }
283                 }
284         },
285         {
286                 .local_name = "whenCreated",
287                 .type = MAP_RENAME,
288                 .u = {
289                         .rename = {
290                                  .remote_name = "createTimestamp"
291                          }
292                 }
293         },
294         {
295                 .local_name = "whenChanged",
296                 .type = MAP_RENAME,
297                 .u = {
298                         .rename = {
299                                  .remote_name = "modifyTimestamp"
300                          }
301                 }
302         },
303         {
304                 .local_name = "objectClasses",
305                 .type = MAP_RENAME,
306                 .u = {
307                         .rename = {
308                                  .remote_name = "samba4ObjectClasses"
309                          }
310                 }
311         },
312         {
313                 .local_name = "dITContentRules",
314                 .type = MAP_RENAME,
315                 .u = {
316                         .rename = {
317                                  .remote_name = "samba4DITContentRules"
318                          }
319                 }
320         },
321         {
322                 .local_name = "attributeTypes",
323                 .type = MAP_RENAME,
324                 .u = {
325                         .rename = {
326                                  .remote_name = "samba4AttributeTypes"
327                          }
328                 }
329         },
330         {
331                 .local_name = "objectCategory",
332                 .type = MAP_CONVERT,
333                 .u = {
334                         .convert = {
335                                 .remote_name = "objectCategory", 
336                                 .convert_local = objectCategory_always_dn,
337                                 .convert_remote = val_copy,
338                         },
339                 },
340         },
341         {
342                 .local_name = "distinguishedName",
343                 .type = MAP_RENAME,
344                 .u = {
345                         .rename = {
346                                  .remote_name = "entryDN"
347                          }
348                 }
349         },
350         {
351                 .local_name = "groupType",
352                 .type = MAP_CONVERT,
353                 .u = {
354                         .convert = {
355                                  .remote_name = "groupType",
356                                  .convert_local = normalise_to_signed32,
357                                  .convert_remote = val_copy,
358                          },
359                 }
360         },
361         {
362                 .local_name = "sAMAccountType",
363                 .type = MAP_CONVERT,
364                 .u = {
365                         .convert = {
366                                  .remote_name = "sAMAccountType",
367                                  .convert_local = normalise_to_signed32,
368                                  .convert_remote = val_copy,
369                          },
370                 }
371         },
372         {
373                 .local_name = "usnChanged",
374                 .type = MAP_CONVERT,
375                 .u = {
376                         .convert = {
377                                  .remote_name = "entryCSN",
378                                  .convert_local = usn_to_entryCSN,
379                                  .convert_remote = entryCSN_to_usn
380                          },
381                 },
382         },
383         {
384                 .local_name = "usnCreated",
385                 .type = MAP_CONVERT,
386                 .u = {
387                         .convert = {
388                                  .remote_name = "createTimestamp",
389                                  .convert_local = usn_to_timestamp,
390                                  .convert_remote = timestamp_to_usn,
391                          },
392                 },
393         },
394         {
395                 .local_name = "*",
396                 .type = MAP_KEEP,
397         },
398         {
399                 .local_name = NULL,
400         }
401 };
402
403 /* This objectClass conflicts with builtin classes on OpenLDAP */
404 const struct ldb_map_objectclass entryuuid_objectclasses[] =
405 {
406         {
407                 .local_name = "subSchema",
408                 .remote_name = "samba4SubSchema"
409         },
410         {
411                 .local_name = NULL
412         }
413 };
414
415 /* These things do not show up in wildcard searches in OpenLDAP, but
416  * we need them to show up in the AD-like view */
417 static const char * const entryuuid_wildcard_attributes[] = {
418         "objectGUID", 
419         "whenCreated", 
420         "whenChanged",
421         "usnCreated",
422         "usnChanged",
423         "memberOf",
424         NULL
425 };
426
427 static const struct ldb_map_attribute nsuniqueid_attributes[] = 
428 {
429         /* objectGUID */
430         {
431                 .local_name = "objectGUID",
432                 .type = MAP_CONVERT,
433                 .u = {
434                         .convert = {
435                                 .remote_name = "nsuniqueid", 
436                                 .convert_local = guid_ns_string,
437                                 .convert_remote = encode_ns_guid,
438                         },
439                 },
440         },
441         /* objectSid */ 
442         {
443                 .local_name = "objectSid",
444                 .type = MAP_CONVERT,
445                 .u = {
446                         .convert = {
447                                 .remote_name = "objectSid", 
448                                 .convert_local = sid_always_binary,
449                                 .convert_remote = val_copy,
450                         },
451                 },
452         },
453         {
454                 .local_name = "whenCreated",
455                 .type = MAP_RENAME,
456                 .u = {
457                         .rename = {
458                                  .remote_name = "createTimestamp"
459                          }
460                 }
461         },
462         {
463                 .local_name = "whenChanged",
464                 .type = MAP_RENAME,
465                 .u = {
466                         .rename = {
467                                  .remote_name = "modifyTimestamp"
468                          }
469                 }
470         },
471         {
472                 .local_name = "objectCategory",
473                 .type = MAP_CONVERT,
474                 .u = {
475                         .convert = {
476                                 .remote_name = "objectCategory", 
477                                 .convert_local = objectCategory_always_dn,
478                                 .convert_remote = val_copy,
479                         },
480                 },
481         },
482         {
483                 .local_name = "distinguishedName",
484                 .type = MAP_RENAME,
485                 .u = {
486                         .rename = {
487                                  .remote_name = "entryDN"
488                          }
489                 }
490         },
491         {
492                 .local_name = "groupType",
493                 .type = MAP_CONVERT,
494                 .u = {
495                         .convert = {
496                                  .remote_name = "groupType",
497                                  .convert_local = normalise_to_signed32,
498                                  .convert_remote = val_copy,
499                          },
500                 }
501         },
502         {
503                 .local_name = "sAMAccountType",
504                 .type = MAP_CONVERT,
505                 .u = {
506                         .convert = {
507                                  .remote_name = "sAMAccountType",
508                                  .convert_local = normalise_to_signed32,
509                                  .convert_remote = val_copy,
510                          },
511                 }
512         },
513         {
514                 .local_name = "usnChanged",
515                 .type = MAP_CONVERT,
516                 .u = {
517                         .convert = {
518                                  .remote_name = "modifyTimestamp",
519                                  .convert_local = usn_to_timestamp,
520                                  .convert_remote = timestamp_to_usn,
521                          },
522                 },
523         },
524         {
525                 .local_name = "usnCreated",
526                 .type = MAP_CONVERT,
527                 .u = {
528                         .convert = {
529                                  .remote_name = "createTimestamp",
530                                  .convert_local = usn_to_timestamp,
531                                  .convert_remote = timestamp_to_usn,
532                          },
533                 },
534         },
535         {
536                 .local_name = "*",
537                 .type = MAP_KEEP,
538         },
539         {
540                 .local_name = NULL,
541         }
542 };
543
544 /* These things do not show up in wildcard searches in OpenLDAP, but
545  * we need them to show up in the AD-like view */
546 static const char * const nsuniqueid_wildcard_attributes[] = {
547         "objectGUID", 
548         "whenCreated", 
549         "whenChanged",
550         "usnCreated",
551         "usnChanged",
552         NULL
553 };
554
555 /* the context init function */
556 static int entryuuid_init(struct ldb_module *module)
557 {
558         int ret;
559         ret = ldb_map_init(module, entryuuid_attributes, entryuuid_objectclasses, entryuuid_wildcard_attributes, "samba4Top", NULL);
560         if (ret != LDB_SUCCESS)
561                 return ret;
562
563         return ldb_next_init(module);
564 }
565
566 /* the context init function */
567 static int nsuniqueid_init(struct ldb_module *module)
568 {
569         int ret;
570         ret = ldb_map_init(module, nsuniqueid_attributes, NULL, nsuniqueid_wildcard_attributes, "extensibleObject", NULL);
571         if (ret != LDB_SUCCESS)
572                 return ret;
573
574         return ldb_next_init(module);
575 }
576
577 static int get_seq_callback(struct ldb_request *req,
578                             struct ldb_reply *ares)
579 {
580         unsigned long long *seq = (unsigned long long *)req->context;
581
582         if (!ares) {
583                 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
584         }
585         if (ares->error != LDB_SUCCESS) {
586                 return ldb_request_done(req, ares->error);
587         }
588
589         if (ares->type == LDB_REPLY_ENTRY) {
590                 struct ldb_message_element *el = ldb_msg_find_element(ares->message, "contextCSN");
591                 if (el) {
592                         *seq = entryCSN_to_usn_int(ares, &el->values[0]);
593                 }
594         }
595
596         if (ares->type == LDB_REPLY_DONE) {
597                 return ldb_request_done(req, LDB_SUCCESS);
598         }
599
600         talloc_free(ares);
601         return LDB_SUCCESS;
602 }
603
604 static int entryuuid_sequence_number(struct ldb_module *module, struct ldb_request *req)
605 {
606         struct ldb_context *ldb;
607         int ret;
608         struct map_private *map_private;
609         struct entryuuid_private *entryuuid_private;
610         unsigned long long seq_num = 0;
611         struct ldb_request *search_req;
612
613         const struct ldb_control *partition_ctrl;
614         const struct dsdb_control_current_partition *partition;
615  
616         static const char *contextCSN_attr[] = {
617                 "contextCSN", NULL
618         };
619
620         struct ldb_seqnum_request *seq;
621         struct ldb_seqnum_result *seqr;
622         struct ldb_extended *ext;
623
624         ldb = ldb_module_get_ctx(module);
625
626         seq = talloc_get_type(req->op.extended.data, struct ldb_seqnum_request);
627
628         map_private = talloc_get_type(ldb_module_get_private(module), struct map_private);
629
630         entryuuid_private = talloc_get_type(map_private->caller_private, struct entryuuid_private);
631
632         /* All this to get the DN of the parition, so we can search the right thing */
633         partition_ctrl = ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID);
634         if (!partition_ctrl) {
635                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
636                               "entryuuid_sequence_number: no current partition control found");
637                 return LDB_ERR_CONSTRAINT_VIOLATION;
638         }
639
640         partition = talloc_get_type(partition_ctrl->data,
641                                     struct dsdb_control_current_partition);
642         SMB_ASSERT(partition && partition->version == DSDB_CONTROL_CURRENT_PARTITION_VERSION);
643
644         ret = ldb_build_search_req(&search_req, ldb, req,
645                                    partition->dn, LDB_SCOPE_BASE,
646                                    NULL, contextCSN_attr, NULL,
647                                    &seq_num, get_seq_callback,
648                                    NULL);
649         if (ret != LDB_SUCCESS) {
650                 return ret;
651         }
652
653         ret = ldb_next_request(module, search_req);
654
655         if (ret == LDB_SUCCESS) {
656                 ret = ldb_wait(search_req->handle, LDB_WAIT_ALL);
657         }
658
659         talloc_free(search_req);
660         if (ret != LDB_SUCCESS) {
661                 return ret;
662         }
663
664         ext = talloc_zero(req, struct ldb_extended);
665         if (!ext) {
666                 return LDB_ERR_OPERATIONS_ERROR;
667         }
668         seqr = talloc_zero(req, struct ldb_seqnum_result);
669         if (seqr == NULL) {
670                 talloc_free(ext);
671                 return LDB_ERR_OPERATIONS_ERROR;
672         }
673         ext->oid = LDB_EXTENDED_SEQUENCE_NUMBER;
674         ext->data = seqr;
675
676         switch (seq->type) {
677         case LDB_SEQ_HIGHEST_SEQ:
678                 seqr->seq_num = seq_num;
679                 break;
680         case LDB_SEQ_NEXT:
681                 seqr->seq_num = seq_num;
682                 seqr->seq_num++;
683                 break;
684         case LDB_SEQ_HIGHEST_TIMESTAMP:
685         {
686                 seqr->seq_num = (seq_num >> 24);
687                 break;
688         }
689         }
690         seqr->flags = 0;
691         seqr->flags |= LDB_SEQ_TIMESTAMP_SEQUENCE;
692         seqr->flags |= LDB_SEQ_GLOBAL_SEQUENCE;
693
694         /* send request done */
695         return ldb_module_done(req, NULL, ext, LDB_SUCCESS);
696 }
697
698 static int entryuuid_extended(struct ldb_module *module, struct ldb_request *req)
699 {
700         if (strcmp(req->op.extended.oid, LDB_EXTENDED_SEQUENCE_NUMBER) == 0) {
701                 return entryuuid_sequence_number(module, req);
702         }
703
704         return ldb_next_request(module, req);
705 }
706
707 _PUBLIC_ const struct ldb_module_ops ldb_entryuuid_module_ops = {
708         .name              = "entryuuid",
709         .init_context      = entryuuid_init,
710         .extended          = entryuuid_extended,
711         LDB_MAP_OPS
712 };
713
714 _PUBLIC_ const struct ldb_module_ops ldb_nsuniqueid_module_ops = {
715         .name              = "nsuniqueid",
716         .init_context      = nsuniqueid_init,
717         .extended          = entryuuid_extended,
718         LDB_MAP_OPS
719 };