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