r17525: This is a merge from the Google Summer of Code 2006 project by Martin Kühl
[gd/samba-autobuild/.git] / source4 / dsdb / samdb / ldb_modules / samba3sam.c
1 /* 
2    ldb database library - Samba3 SAM compatibility backend
3
4    Copyright (C) Jelmer Vernooij 2005
5 */
6
7 #include "includes.h"
8 #include "ldb/include/ldb.h"
9 #include "ldb/include/ldb_private.h"
10 #include "ldb/include/ldb_errors.h"
11 #include "ldb/modules/ldb_map.h"
12 #include "system/passwd.h"
13
14 #include "librpc/gen_ndr/ndr_security.h"
15 #include "librpc/ndr/libndr.h"
16 #include "libcli/security/security.h"
17 #include "libcli/security/proto.h"
18
19 /* 
20  * sambaSID -> member  (dn!)
21  * sambaSIDList -> member (dn!) 
22  * sambaDomainName -> name 
23  * sambaTrustPassword 
24  * sambaUnixIdPool 
25  * sambaIdmapEntry 
26  * sambaAccountPolicy 
27  * sambaSidEntry 
28  * sambaAcctFlags -> systemFlags ?
29  * sambaPasswordHistory  -> ntPwdHistory*/
30
31 /* Not necessary:
32  * sambaConfig
33  * sambaShare
34  * sambaConfigOption 
35  * sambaNextGroupRid
36  * sambaNextUserRid
37  * sambaAlgorithmicRidBase
38  */
39
40 /* Not in Samba4: 
41  * sambaKickoffTime
42  * sambaPwdCanChange
43  * sambaPwdMustChange
44  * sambaHomePath
45  * sambaHomeDrive
46  * sambaLogonScript
47  * sambaProfilePath
48  * sambaUserWorkstations
49  * sambaMungedDial
50  * sambaLogonHours */
51
52 /* In Samba4 but not in Samba3:
53 */
54
55 static struct ldb_message_element *generate_primaryGroupID(struct ldb_module *module, TALLOC_CTX *ctx, const char *attr, const struct ldb_message *remote)
56 {
57         struct ldb_message_element *el;
58         const char *sid = ldb_msg_find_attr_as_string(remote, attr, NULL);
59
60         if (!sid)
61                 return NULL;
62
63         if (strchr(sid, '-') == NULL)
64                 return NULL;
65
66         el = talloc_zero(ctx, struct ldb_message_element);
67         el->name = talloc_strdup(ctx, "primaryGroupID");
68         el->num_values = 1;
69         el->values = talloc_array(ctx, struct ldb_val, 1);
70         el->values[0].data = (uint8_t *)talloc_strdup(ctx, strchr(sid, '-')+1);
71         el->values[0].length = strlen((char *)el->values[0].data);
72
73         return el;
74 }
75
76 static void generate_sambaPrimaryGroupSID(struct ldb_module *module, const char *local_attr, const struct ldb_message *local, struct ldb_message *remote_mp, struct ldb_message *remote_fb)
77 {
78         const struct ldb_val *sidval;
79         char *sidstring;
80         struct dom_sid *sid;
81         NTSTATUS status;
82
83         sidval = ldb_msg_find_ldb_val(local, "objectSid");
84
85         if (!sidval) 
86                 return; /* Sorry, no SID today.. */
87
88         sid = talloc(remote_mp, struct dom_sid);
89         if (sid == NULL) {
90                 return;
91         }
92         status = ndr_pull_struct_blob(sidval, sid, sid, (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
93         if (!NT_STATUS_IS_OK(status)) {
94                 talloc_free(sid);
95                 return;
96         }
97
98         if (!ldb_msg_find_ldb_val(local, "primaryGroupID"))
99                 return; /* Sorry, no SID today.. */
100
101         sid->num_auths--;
102
103         sidstring = dom_sid_string(remote_mp, sid);
104         talloc_free(sid);
105         ldb_msg_add_fmt(remote_mp, "sambaPrimaryGroupSID", "%s-%d", sidstring, ldb_msg_find_attr_as_uint(local, "primaryGroupID", 0));
106         talloc_free(sidstring);
107 }
108
109 static struct ldb_val convert_uid_samaccount(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
110 {
111         return ldb_val_dup(ctx, val);
112 }
113
114 static struct ldb_val lookup_homedir(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
115 {
116         struct passwd *pwd; 
117         struct ldb_val retval;
118         
119         pwd = getpwnam((char *)val->data);
120
121         if (!pwd) {
122                 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Unable to lookup '%s' in passwd", (char *)val->data);
123                 return *talloc_zero(ctx, struct ldb_val);
124         }
125
126         retval.data = (uint8_t *)talloc_strdup(ctx, pwd->pw_dir);
127         retval.length = strlen((char *)retval.data);
128
129         return retval;
130 }
131
132 static struct ldb_val lookup_gid(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
133 {
134         struct passwd *pwd; 
135         struct ldb_val retval;
136         
137         pwd = getpwnam((char *)val->data);
138
139         if (!pwd) {
140                 return *talloc_zero(ctx, struct ldb_val);
141         }
142
143         retval.data = (uint8_t *)talloc_asprintf(ctx, "%ld", (unsigned long)pwd->pw_gid);
144         retval.length = strlen((char *)retval.data);
145
146         return retval;
147 }
148
149 static struct ldb_val lookup_uid(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
150 {
151         struct passwd *pwd; 
152         struct ldb_val retval;
153         
154         pwd = getpwnam((char *)val->data);
155
156         if (!pwd) {
157                 return *talloc_zero(ctx, struct ldb_val);
158         }
159
160         retval.data = (uint8_t *)talloc_asprintf(ctx, "%ld", (unsigned long)pwd->pw_uid);
161         retval.length = strlen((char *)retval.data);
162
163         return retval;
164 }
165
166 static struct ldb_val encode_sid(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
167 {
168         struct dom_sid *sid = dom_sid_parse_talloc(ctx, (char *)val->data);
169         struct ldb_val *out = talloc_zero(ctx, struct ldb_val);
170         NTSTATUS status;
171
172         if (sid == NULL) {
173                 return *out;
174         }
175         status = ndr_push_struct_blob(out, ctx, sid, 
176                                       (ndr_push_flags_fn_t)ndr_push_dom_sid);
177         talloc_free(sid);
178         if (!NT_STATUS_IS_OK(status)) {
179                 return *out;
180         }
181
182         return *out;
183 }
184
185 static struct ldb_val decode_sid(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
186 {
187         struct dom_sid *sid;
188         NTSTATUS status;
189         struct ldb_val *out = talloc_zero(ctx, struct ldb_val);
190         
191         sid = talloc(ctx, struct dom_sid);
192         if (sid == NULL) {
193                 return *out;
194         }
195         status = ndr_pull_struct_blob(val, sid, sid, 
196                                       (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
197         if (!NT_STATUS_IS_OK(status)) {
198                 talloc_free(sid);
199                 return *out;
200         }
201         out->data = (uint8_t *)dom_sid_string(ctx, sid);
202         talloc_free(sid);
203         if (out->data == NULL) {
204                 return *out;
205         }
206         out->length = strlen((const char *)out->data);
207
208         return *out;
209 }
210
211 const struct ldb_map_objectclass samba3_objectclasses[] = {
212         {
213                 .local_name = "user",
214                 .remote_name = "posixAccount",
215                 .base_classes = { "top", NULL },
216                 .musts = { "cn", "uid", "uidNumber", "gidNumber", "homeDirectory", NULL },
217                 .mays = { "userPassword", "loginShell", "gecos", "description", NULL },
218         },
219         {
220                 .local_name = "group",
221                 .remote_name = "posixGroup",
222                 .base_classes = { "top", NULL },
223                 .musts = { "cn", "gidNumber", NULL },
224                 .mays = { "userPassword", "memberUid", "description", NULL },
225         },
226         { 
227                 .local_name = "group", 
228                 .remote_name = "sambaGroupMapping",
229                 .base_classes = { "top", "posixGroup", NULL },
230                 .musts = { "gidNumber", "sambaSID", "sambaGroupType", NULL },
231                 .mays = { "displayName", "description", "sambaSIDList", NULL },
232         },
233         { 
234                 .local_name = "user", 
235                 .remote_name = "sambaSAMAccount",
236                 .base_classes = { "top", "posixAccount", NULL },
237                 .musts = { "uid", "sambaSID", NULL },
238                 .mays = { "cn", "sambaLMPassword", "sambaNTPassword",
239                         "sambaPwdLastSet", "sambaLogonTime", "sambaLogoffTime",
240                         "sambaKickoffTime", "sambaPwdCanChange", "sambaPwdMustChange",
241                         "sambaAcctFlags", "displayName", "sambaHomePath", "sambaHomeDrive",
242                         "sambaLogonScript", "sambaProfilePath", "description", "sambaUserWorkstations",
243                         "sambaPrimaryGroupSID", "sambaDomainName", "sambaMungedDial",
244                         "sambaBadPasswordCount", "sambaBadPasswordTime",
245                 "sambaPasswordHistory", "sambaLogonHours", NULL }
246         
247         },
248         { 
249                 .local_name = "domain", 
250                 .remote_name = "sambaDomain",
251                 .base_classes = { "top", NULL },
252                 .musts = { "sambaDomainName", "sambaSID", NULL },
253                 .mays = { "sambaNextRid", "sambaNextGroupRid", "sambaNextUserRid", "sambaAlgorithmicRidBase", NULL },
254         },
255                 { NULL, NULL }
256 };
257
258 const struct ldb_map_attribute samba3_attributes[] = 
259 {
260         /* sambaNextRid -> nextRid */
261         {
262                 .local_name = "nextRid",
263                 .type = MAP_RENAME,
264                 .u = {
265                         .rename = {
266                                 .remote_name = "sambaNextRid",
267                         },
268                 },
269         },
270
271         /* sambaBadPasswordTime -> badPasswordtime*/
272         {
273                 .local_name = "badPasswordTime",
274                 .type = MAP_RENAME,
275                 .u = {
276                         .rename = {
277                                 .remote_name = "sambaBadPasswordTime",
278                         },
279                 },
280         },
281
282         /* sambaLMPassword -> lmPwdHash*/
283         {
284                 .local_name = "lmPwdHash",
285                 .type = MAP_RENAME,
286                 .u = {
287                         .rename = {
288                                 .remote_name = "sambaLMPassword",
289                         },
290                 },
291         },
292
293         /* sambaGroupType -> groupType */
294         {
295                 .local_name = "groupType",
296                 .type = MAP_RENAME,
297                 .u = {
298                         .rename = {
299                                 .remote_name = "sambaGroupType",
300                         },
301                 },
302         },
303
304         /* sambaNTPassword -> ntPwdHash*/
305         {
306                 .local_name = "ntPwdHash",
307                 .type = MAP_RENAME,
308                 .u = {
309                         .rename = {
310                                 .remote_name = "sambaNTPassword",
311                         },
312                 },
313         },
314
315         /* sambaPrimaryGroupSID -> primaryGroupID */
316         {
317                 .local_name = "primaryGroupID",
318                 .type = MAP_GENERATE,
319                 .u = {
320                         .generate = {
321                                 .remote_names = { "sambaPrimaryGroupSID", NULL },
322                                 .generate_local = generate_primaryGroupID,
323                                 .generate_remote = generate_sambaPrimaryGroupSID, 
324                         },
325                 },
326         },
327
328         /* sambaBadPasswordCount -> badPwdCount */
329         {
330                 .local_name = "badPwdCount",
331                 .type = MAP_RENAME,
332                 .u = {
333                         .rename = {
334                                 .remote_name = "sambaBadPasswordCount",
335                         },
336                 },
337         },
338
339         /* sambaLogonTime -> lastLogon*/
340         {
341                 .local_name = "lastLogon",
342                 .type = MAP_RENAME,
343                 .u = {
344                         .rename = {
345                                 .remote_name = "sambaLogonTime",
346                         },
347                 },
348         },
349
350         /* sambaLogoffTime -> lastLogoff*/
351         {
352                 .local_name = "lastLogoff",
353                 .type = MAP_RENAME,
354                 .u = {
355                         .rename = {
356                                 .remote_name = "sambaLogoffTime",
357                         },
358                 },
359         },
360
361         /* uid -> unixName */
362         {
363                 .local_name = "unixName",
364                 .type = MAP_RENAME,
365                 .u = {
366                         .rename = {
367                                 .remote_name = "uid",
368                         },
369                 },
370         },
371
372         /* displayName -> name */
373         {
374                 .local_name = "name",
375                 .type = MAP_RENAME,
376                 .u = {
377                         .rename = {
378                                 .remote_name = "displayName",
379                         },
380                 },
381         },
382
383         /* cn */
384         {
385                 .local_name = "cn",
386                 .type = MAP_KEEP,
387         },
388
389         /* sAMAccountName -> cn */
390         {
391                 .local_name = "sAMAccountName",
392                 .type = MAP_CONVERT,
393                 .u = {
394                         .convert = {
395                                 .remote_name = "uid",
396                                 .convert_remote = convert_uid_samaccount,
397                         },
398                 },
399         },
400
401         /* objectCategory */
402         {
403                 .local_name = "objectCategory",
404                 .type = MAP_IGNORE,
405         },
406
407         /* objectGUID */
408         {
409                 .local_name = "objectGUID",
410                 .type = MAP_IGNORE,
411         },
412
413         /* objectVersion */
414         {
415                 .local_name = "objectVersion",
416                 .type = MAP_IGNORE,
417         },
418
419         /* codePage */
420         { 
421                 .local_name = "codePage",
422                 .type = MAP_IGNORE,
423         },
424
425         /* dNSHostName */
426         {
427                 .local_name = "dNSHostName",
428                 .type = MAP_IGNORE,
429         },
430
431
432         /* dnsDomain */
433         {
434                 .local_name = "dnsDomain",
435                 .type = MAP_IGNORE,
436         },
437
438         /* dnsRoot */
439         {
440                 .local_name = "dnsRoot",
441                 .type = MAP_IGNORE,
442         },
443
444         /* countryCode */
445         {
446                 .local_name = "countryCode",
447                 .type = MAP_IGNORE,
448         },
449
450         /* nTMixedDomain */
451         { 
452                 .local_name = "nTMixedDomain",
453                 .type = MAP_IGNORE,
454         },
455
456         /* operatingSystem */
457         { 
458                 .local_name = "operatingSystem",
459                 .type = MAP_IGNORE,
460         },
461
462         /* operatingSystemVersion */
463         {
464                 .local_name = "operatingSystemVersion",
465                 .type = MAP_IGNORE,
466         },
467
468
469         /* servicePrincipalName */
470         {
471                 .local_name = "servicePrincipalName",
472                 .type = MAP_IGNORE,
473         },
474
475         /* msDS-Behavior-Version */
476         {
477                 .local_name = "msDS-Behavior-Version",
478                 .type = MAP_IGNORE,
479         },
480
481         /* msDS-KeyVersionNumber */
482         {
483                 .local_name = "msDS-KeyVersionNumber",
484                 .type = MAP_IGNORE,
485         },
486
487         /* msDs-masteredBy */
488         {
489                 .local_name = "msDs-masteredBy",
490                 .type = MAP_IGNORE,
491         },
492
493         /* ou */
494         {
495                 .local_name = "ou",
496                 .type = MAP_KEEP,
497         },
498
499         /* dc */
500         {
501                 .local_name = "dc",
502                 .type = MAP_KEEP,
503         },
504
505         /* description */
506         {
507                 .local_name = "description",
508                 .type = MAP_KEEP,
509         },
510
511         /* sambaSID -> objectSid*/
512         {
513                 .local_name = "objectSid",
514                 .type = MAP_CONVERT,
515                 .u = {
516                         .convert = {
517                                 .remote_name = "sambaSID", 
518                                 .convert_local = decode_sid,
519                                 .convert_remote = encode_sid,
520                         },
521                 },
522         },
523
524         /* sambaPwdLastSet -> pwdLastSet */
525         {
526                 .local_name = "pwdLastSet",
527                 .type = MAP_RENAME,
528                 .u = {
529                         .rename = {
530                                 .remote_name = "sambaPwdLastSet",
531                         },
532                 },
533         },      
534
535         /* accountExpires */
536         {
537                 .local_name = "accountExpires", 
538                 .type = MAP_IGNORE,
539         },
540
541         /* adminCount */
542         {
543                 .local_name = "adminCount",
544                 .type = MAP_IGNORE,
545         },
546
547         /* canonicalName */
548         {
549                 .local_name = "canonicalName",
550                 .type = MAP_IGNORE,
551         },
552
553         /* createTimestamp */
554         {
555                 .local_name = "createTimestamp",
556                 .type = MAP_IGNORE,
557         },
558         
559         /* creationTime */
560         {
561                 .local_name = "creationTime",
562                 .type = MAP_IGNORE,
563         },
564         
565         /* dMDLocation */
566         {
567                 .local_name = "dMDLocation",
568                 .type = MAP_IGNORE,
569         },
570         
571         /* fSMORoleOwner */
572         {
573                 .local_name = "fSMORoleOwner",
574                 .type = MAP_IGNORE,
575         },
576         
577         /* forceLogoff */
578         {
579                 .local_name = "forceLogoff",
580                 .type = MAP_IGNORE,
581         },
582         
583         /* instanceType */
584         {
585                 .local_name = "instanceType",
586                 .type = MAP_IGNORE,
587         },
588         
589         /* invocationId */
590         {
591                 .local_name = "invocationId",
592                 .type = MAP_IGNORE,
593         },
594         
595         /* isCriticalSystemObject */
596         {
597                 .local_name = "isCriticalSystemObject",
598                 .type = MAP_IGNORE,
599         },
600         
601         /* localPolicyFlags */
602         {
603                 .local_name = "localPolicyFlags",
604                 .type = MAP_IGNORE,
605         },
606         
607         /* lockOutObservationWindow */
608         {
609                 .local_name = "lockOutObservationWindow",
610                 .type = MAP_IGNORE,
611         },
612
613         /* lockoutDuration */
614         {
615                 .local_name = "lockoutDuration",
616                 .type = MAP_IGNORE,
617         },
618
619         /* lockoutThreshold */
620         {
621                 .local_name = "lockoutThreshold",
622                 .type = MAP_IGNORE,
623         },
624
625         /* logonCount */
626         {
627                 .local_name = "logonCount",
628                 .type = MAP_IGNORE,
629         },
630
631         /* masteredBy */
632         {
633                 .local_name = "masteredBy",
634                 .type = MAP_IGNORE,
635         },
636
637         /* maxPwdAge */
638         {
639                 .local_name = "maxPwdAge",
640                 .type = MAP_IGNORE,
641         },
642
643         /* member */
644         {
645                 .local_name = "member",
646                 .type = MAP_IGNORE,
647         },
648
649         /* memberOf */
650         {
651                 .local_name = "memberOf",
652                 .type = MAP_IGNORE,
653         },
654
655         /* minPwdAge */
656         {
657                 .local_name = "minPwdAge",
658                 .type = MAP_IGNORE,
659         },
660
661         /* minPwdLength */
662         {
663                 .local_name = "minPwdLength",
664                 .type = MAP_IGNORE,
665         },
666
667         /* modifiedCount */
668         {
669                 .local_name = "modifiedCount",
670                 .type = MAP_IGNORE,
671         },
672
673         /* modifiedCountAtLastProm */
674         {
675                 .local_name = "modifiedCountAtLastProm",
676                 .type = MAP_IGNORE,
677         },
678
679         /* modifyTimestamp */
680         {
681                 .local_name = "modifyTimestamp",
682                 .type = MAP_IGNORE,
683         },
684
685         /* nCName */
686         {
687                 .local_name = "nCName",
688                 .type = MAP_IGNORE,
689         },
690
691         /* nETBIOSName */
692         {
693                 .local_name = "nETBIOSName",
694                 .type = MAP_IGNORE,
695         },
696
697         /* oEMInformation */
698         {
699                 .local_name = "oEMInformation",
700                 .type = MAP_IGNORE,
701         },
702
703         /* privilege */
704         {
705                 .local_name = "privilege",
706                 .type = MAP_IGNORE,
707         },
708
709         /* pwdHistoryLength */
710         {
711                 .local_name = "pwdHistoryLength",
712                 .type = MAP_IGNORE,
713         },
714
715         /* pwdProperties */
716         {
717                 .local_name = "pwdProperties",
718                 .type = MAP_IGNORE,
719         },
720
721         /* rIDAvailablePool */
722         {
723                 .local_name = "rIDAvailablePool",
724                 .type = MAP_IGNORE,
725         },
726
727         /* revision */
728         {
729                 .local_name = "revision",
730                 .type = MAP_IGNORE,
731         },
732
733         /* ridManagerReference */
734         {
735                 .local_name = "ridManagerReference",
736                 .type = MAP_IGNORE,
737         },
738
739         /* sAMAccountType */
740         {
741                 .local_name = "sAMAccountType",
742                 .type = MAP_IGNORE,
743         },
744
745         /* sPNMappings */
746         {
747                 .local_name = "sPNMappings",
748                 .type = MAP_IGNORE,
749         },
750
751         /* serverReference */
752         {
753                 .local_name = "serverReference",
754                 .type = MAP_IGNORE,
755         },
756
757         /* serverState */
758         {
759                 .local_name = "serverState",
760                 .type = MAP_IGNORE,
761         },
762
763         /* showInAdvancedViewOnly */
764         {
765                 .local_name = "showInAdvancedViewOnly",
766                 .type = MAP_IGNORE,
767         },
768
769         /* subRefs */
770         {
771                 .local_name = "subRefs",
772                 .type = MAP_IGNORE,
773         },
774
775         /* systemFlags */
776         {
777                 .local_name = "systemFlags",
778                 .type = MAP_IGNORE,
779         },
780
781         /* uASCompat */
782         {
783                 .local_name = "uASCompat",
784                 .type = MAP_IGNORE,
785         },
786
787         /* uSNChanged */
788         {
789                 .local_name = "uSNChanged",
790                 .type = MAP_IGNORE,
791         },
792
793         /* uSNCreated */
794         {
795                 .local_name = "uSNCreated",
796                 .type = MAP_IGNORE,
797         },
798
799         /* sambaPassword */
800         {
801                 .local_name = "sambaPassword",
802                 .type = MAP_IGNORE,
803         },
804
805         /* userAccountControl */
806         {
807                 .local_name = "userAccountControl",
808                 .type = MAP_IGNORE,
809         },
810
811         /* whenChanged */
812         {
813                 .local_name = "whenChanged",
814                 .type = MAP_IGNORE,
815         },
816
817         /* whenCreated */
818         {
819                 .local_name = "whenCreated",
820                 .type = MAP_IGNORE,
821         },
822
823         /* uidNumber */
824         {
825                 .local_name = "unixName",
826                 .type = MAP_CONVERT,
827                 .u = {
828                         .convert = {
829                                 .remote_name = "uidNumber",
830                                 .convert_local = lookup_uid,
831                         },
832                 },
833         },
834
835         /* gidNumber. Perhaps make into generate so we can distinguish between 
836          * groups and accounts? */
837         {
838                 .local_name = "unixName",
839                 .type = MAP_CONVERT,
840                 .u = {
841                         .convert = {
842                                 .remote_name = "gidNumber",
843                                 .convert_local = lookup_gid,
844                         },
845                 },
846         },
847
848         /* homeDirectory */
849         {
850                 .local_name = "unixName",
851                 .type = MAP_CONVERT,
852                 .u = {
853                         .convert = {
854                                 .remote_name = "homeDirectory",
855                                 .convert_local = lookup_homedir,
856                         },
857                 },
858         },
859         {
860                 .local_name = NULL,
861         }
862 };
863
864 /* the context init function */
865 static int samba3sam_init(struct ldb_module *module)
866 {
867         int ret;
868
869         ret = ldb_map_init(module, samba3_attributes, samba3_objectclasses, "samba3sam");
870         if (ret != LDB_SUCCESS)
871                 return ret;
872
873         return ldb_next_init(module);
874 }
875
876 static struct ldb_module_ops samba3sam_ops = {
877         .name              = "samba3sam",
878         .init_context      = samba3sam_init,
879 };
880
881 /* the init function */
882 int ldb_samba3sam_module_init(void)
883 {
884         struct ldb_module_ops ops = ldb_map_get_ops();
885         samba3sam_ops.add       = ops.add;
886         samba3sam_ops.modify    = ops.modify;
887         samba3sam_ops.del       = ops.del;
888         samba3sam_ops.rename    = ops.rename;
889         samba3sam_ops.search    = ops.search;
890         samba3sam_ops.wait      = ops.wait;
891
892         return ldb_register_module(&samba3sam_ops);
893 }