dsdb: Ensure to sort replPropertyMetaData as UNSIGNED, not SIGNED quantities
[Samba.git] / source4 / dsdb / samdb / ldb_modules / samba3sam.c
blobe9830c904560fa33a15fc7bc1dbf54dba92dafa4
1 /*
2 ldb database library - Samba3 SAM compatibility backend
4 Copyright (C) Jelmer Vernooij 2005
5 Copyright (C) Martin Kuehl <mkhl@samba.org> 2006
6 */
8 #include "includes.h"
9 #include "ldb_module.h"
10 #include "ldb/ldb_map/ldb_map.h"
11 #include "system/passwd.h"
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 "lib/samba3/samba3.h"
20 * sambaSID -> member (dn!)
21 * sambaSIDList -> member (dn!)
22 * sambaDomainName -> name
23 * sambaTrustPassword
24 * sambaUnixIdPool
25 * sambaIdmapEntry
26 * sambaSidEntry
27 * sambaAcctFlags -> systemFlags ?
28 * sambaPasswordHistory -> ntPwdHistory*/
30 /* Not necessary:
31 * sambaConfig
32 * sambaShare
33 * sambaConfigOption
34 * sambaNextGroupRid
35 * sambaNextUserRid
36 * sambaAlgorithmicRidBase
39 /* Not in Samba4:
40 * sambaKickoffTime
41 * sambaPwdCanChange
42 * sambaPwdMustChange
43 * sambaHomePath
44 * sambaHomeDrive
45 * sambaLogonScript
46 * sambaProfilePath
47 * sambaUserWorkstations
48 * sambaMungedDial
49 * sambaLogonHours */
51 /* In Samba4 but not in Samba3:
54 /* From a sambaPrimaryGroupSID, generate a primaryGroupID (integer) attribute */
55 static struct ldb_message_element *generate_primaryGroupID(struct ldb_module *module, TALLOC_CTX *ctx, const char *local_attr, const struct ldb_message *remote)
57 struct ldb_message_element *el;
58 const char *sid = ldb_msg_find_attr_as_string(remote, "sambaPrimaryGroupSID", NULL);
59 const char *p;
61 if (!sid)
62 return NULL;
64 p = strrchr(sid, '-');
65 if (!p)
66 return NULL;
68 el = talloc_zero(ctx, struct ldb_message_element);
69 el->name = talloc_strdup(ctx, "primaryGroupID");
70 el->num_values = 1;
71 el->values = talloc_array(ctx, struct ldb_val, 1);
72 el->values[0].data = (uint8_t *)talloc_strdup(el->values, p+1);
73 el->values[0].length = strlen((char *)el->values[0].data);
75 return el;
78 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)
80 const struct ldb_val *sidval;
81 char *sidstring;
82 struct dom_sid *sid;
83 enum ndr_err_code ndr_err;
85 /* We need the domain, so we get it from the objectSid that we hope is here... */
86 sidval = ldb_msg_find_ldb_val(local, "objectSid");
88 if (!sidval)
89 return; /* Sorry, no SID today.. */
91 sid = talloc(remote_mp, struct dom_sid);
92 if (sid == NULL) {
93 return;
96 ndr_err = ndr_pull_struct_blob(sidval, sid, sid, (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
97 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
98 talloc_free(sid);
99 return;
102 if (!ldb_msg_find_ldb_val(local, "primaryGroupID"))
103 return; /* Sorry, no SID today.. */
105 sid->num_auths--;
107 sidstring = dom_sid_string(remote_mp, sid);
108 talloc_free(sid);
109 ldb_msg_add_fmt(remote_mp, "sambaPrimaryGroupSID", "%s-%u", sidstring,
110 ldb_msg_find_attr_as_uint(local, "primaryGroupID", 0));
111 talloc_free(sidstring);
114 /* Just copy the old value. */
115 static struct ldb_val convert_uid_samaccount(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
117 struct ldb_val out = data_blob(NULL, 0);
118 out = ldb_val_dup(ctx, val);
120 return out;
123 static struct ldb_val lookup_homedir(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
125 struct ldb_context *ldb;
126 struct passwd *pwd;
127 struct ldb_val retval;
129 ldb = ldb_module_get_ctx(module);
131 pwd = getpwnam((char *)val->data);
133 if (!pwd) {
134 ldb_debug(ldb, LDB_DEBUG_WARNING, "Unable to lookup '%s' in passwd", (char *)val->data);
135 return *talloc_zero(ctx, struct ldb_val);
138 retval.data = (uint8_t *)talloc_strdup(ctx, pwd->pw_dir);
139 retval.length = strlen((char *)retval.data);
141 return retval;
144 static struct ldb_val lookup_gid(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
146 struct passwd *pwd;
147 struct ldb_val retval;
149 pwd = getpwnam((char *)val->data);
151 if (!pwd) {
152 return *talloc_zero(ctx, struct ldb_val);
155 /* "pw_gid" is per POSIX definition "unsigned".
156 * But write it out as "signed" for LDAP compliance. */
157 retval.data = (uint8_t *)talloc_asprintf(ctx, "%d", (int) pwd->pw_gid);
158 retval.length = strlen((char *)retval.data);
160 return retval;
163 static struct ldb_val lookup_uid(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
165 struct passwd *pwd;
166 struct ldb_val retval;
168 pwd = getpwnam((char *)val->data);
170 if (!pwd) {
171 return *talloc_zero(ctx, struct ldb_val);
174 /* "pw_uid" is per POSIX definition "unsigned".
175 * But write it out as "signed" for LDAP compliance. */
176 retval.data = (uint8_t *)talloc_asprintf(ctx, "%d", (int) pwd->pw_uid);
177 retval.length = strlen((char *)retval.data);
179 return retval;
182 /* Encode a sambaSID to an objectSid. */
183 static struct ldb_val encode_sid(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
185 struct ldb_val out = data_blob(NULL, 0);
186 struct dom_sid *sid;
187 enum ndr_err_code ndr_err;
189 sid = dom_sid_parse_talloc(ctx, (char *)val->data);
190 if (sid == NULL) {
191 return out;
194 ndr_err = ndr_push_struct_blob(&out, ctx,
195 sid, (ndr_push_flags_fn_t)ndr_push_dom_sid);
196 talloc_free(sid);
197 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
198 return out;
201 return out;
204 /* Decode an objectSid to a sambaSID. */
205 static struct ldb_val decode_sid(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
207 struct ldb_val out = data_blob(NULL, 0);
208 struct dom_sid *sid;
209 enum ndr_err_code ndr_err;
211 sid = talloc(ctx, struct dom_sid);
212 if (sid == NULL) {
213 return out;
216 ndr_err = ndr_pull_struct_blob(val, sid, sid,
217 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
218 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
219 goto done;
222 out.data = (uint8_t *)dom_sid_string(ctx, sid);
223 if (out.data == NULL) {
224 goto done;
226 out.length = strlen((const char *)out.data);
228 done:
229 talloc_free(sid);
230 return out;
233 /* Convert 16 bytes to 32 hex digits. */
234 static struct ldb_val bin2hex(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
236 struct ldb_val out;
237 struct samr_Password pwd;
238 if (val->length != sizeof(pwd.hash)) {
239 return data_blob(NULL, 0);
241 memcpy(pwd.hash, val->data, sizeof(pwd.hash));
242 out = data_blob_string_const(smbpasswd_sethexpwd(ctx, &pwd, 0));
243 if (!out.data) {
244 return data_blob(NULL, 0);
246 return out;
249 /* Convert 32 hex digits to 16 bytes. */
250 static struct ldb_val hex2bin(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
252 struct ldb_val out;
253 struct samr_Password *pwd;
254 pwd = smbpasswd_gethexpwd(ctx, (const char *)val->data);
255 if (!pwd) {
256 return data_blob(NULL, 0);
258 out = data_blob_talloc(ctx, pwd->hash, sizeof(pwd->hash));
259 return out;
262 const struct ldb_map_objectclass samba3_objectclasses[] = {
264 .local_name = "user",
265 .remote_name = "posixAccount",
266 .base_classes = { "top", NULL },
267 .musts = { "cn", "uid", "uidNumber", "gidNumber", "homeDirectory", NULL },
268 .mays = { "userPassword", "loginShell", "gecos", "description", NULL },
271 .local_name = "group",
272 .remote_name = "posixGroup",
273 .base_classes = { "top", NULL },
274 .musts = { "cn", "gidNumber", NULL },
275 .mays = { "userPassword", "memberUid", "description", NULL },
278 .local_name = "group",
279 .remote_name = "sambaGroupMapping",
280 .base_classes = { "top", "posixGroup", NULL },
281 .musts = { "gidNumber", "sambaSID", "sambaGroupType", NULL },
282 .mays = { "displayName", "description", "sambaSIDList", NULL },
285 .local_name = "user",
286 .remote_name = "sambaSAMAccount",
287 .base_classes = { "top", "posixAccount", NULL },
288 .musts = { "uid", "sambaSID", NULL },
289 .mays = { "cn", "sambaLMPassword", "sambaNTPassword",
290 "sambaPwdLastSet", "sambaLogonTime", "sambaLogoffTime",
291 "sambaKickoffTime", "sambaPwdCanChange", "sambaPwdMustChange",
292 "sambaAcctFlags", "displayName", "sambaHomePath", "sambaHomeDrive",
293 "sambaLogonScript", "sambaProfilePath", "description", "sambaUserWorkstations",
294 "sambaPrimaryGroupSID", "sambaDomainName", "sambaMungedDial",
295 "sambaBadPasswordCount", "sambaBadPasswordTime",
296 "sambaPasswordHistory", "sambaLogonHours", NULL }
300 .local_name = "domain",
301 .remote_name = "sambaDomain",
302 .base_classes = { "top", NULL },
303 .musts = { "sambaDomainName", "sambaSID", NULL },
304 .mays = { "sambaNextRid", "sambaNextGroupRid", "sambaNextUserRid", "sambaAlgorithmicRidBase", NULL },
306 { NULL, NULL }
309 const struct ldb_map_attribute samba3_attributes[] =
311 /* sambaNextRid -> nextRid */
313 .local_name = "nextRid",
314 .type = LDB_MAP_RENAME,
315 .u = {
316 .rename = {
317 .remote_name = "sambaNextRid",
322 /* sambaBadPasswordTime -> badPasswordtime*/
324 .local_name = "badPasswordTime",
325 .type = LDB_MAP_RENAME,
326 .u = {
327 .rename = {
328 .remote_name = "sambaBadPasswordTime",
333 /* sambaLMPassword -> lmPwdHash*/
335 .local_name = "dBCSPwd",
336 .type = LDB_MAP_CONVERT,
337 .u = {
338 .convert = {
339 .remote_name = "sambaLMPassword",
340 .convert_local = bin2hex,
341 .convert_remote = hex2bin,
346 /* sambaGroupType -> groupType */
348 .local_name = "groupType",
349 .type = LDB_MAP_RENAME,
350 .u = {
351 .rename = {
352 .remote_name = "sambaGroupType",
357 /* sambaNTPassword -> ntPwdHash*/
359 .local_name = "ntpwdhash",
360 .type = LDB_MAP_CONVERT,
361 .u = {
362 .convert = {
363 .remote_name = "sambaNTPassword",
364 .convert_local = bin2hex,
365 .convert_remote = hex2bin,
370 /* sambaPrimaryGroupSID -> primaryGroupID */
372 .local_name = "primaryGroupID",
373 .type = LDB_MAP_GENERATE,
374 .u = {
375 .generate = {
376 .remote_names = { "sambaPrimaryGroupSID", NULL },
377 .generate_local = generate_primaryGroupID,
378 .generate_remote = generate_sambaPrimaryGroupSID,
383 /* sambaBadPasswordCount -> badPwdCount */
385 .local_name = "badPwdCount",
386 .type = LDB_MAP_RENAME,
387 .u = {
388 .rename = {
389 .remote_name = "sambaBadPasswordCount",
394 /* sambaLogonTime -> lastLogon*/
396 .local_name = "lastLogon",
397 .type = LDB_MAP_RENAME,
398 .u = {
399 .rename = {
400 .remote_name = "sambaLogonTime",
405 /* sambaLogoffTime -> lastLogoff*/
407 .local_name = "lastLogoff",
408 .type = LDB_MAP_RENAME,
409 .u = {
410 .rename = {
411 .remote_name = "sambaLogoffTime",
416 /* uid -> unixName */
418 .local_name = "unixName",
419 .type = LDB_MAP_RENAME,
420 .u = {
421 .rename = {
422 .remote_name = "uid",
427 /* displayName -> name */
429 .local_name = "name",
430 .type = LDB_MAP_RENAME,
431 .u = {
432 .rename = {
433 .remote_name = "displayName",
438 /* cn */
440 .local_name = "cn",
441 .type = LDB_MAP_KEEP,
444 /* sAMAccountName -> cn */
446 .local_name = "sAMAccountName",
447 .type = LDB_MAP_CONVERT,
448 .u = {
449 .convert = {
450 .remote_name = "uid",
451 .convert_remote = convert_uid_samaccount,
456 /* objectCategory */
458 .local_name = "objectCategory",
459 .type = LDB_MAP_IGNORE,
462 /* objectGUID */
464 .local_name = "objectGUID",
465 .type = LDB_MAP_IGNORE,
468 /* objectVersion */
470 .local_name = "objectVersion",
471 .type = LDB_MAP_IGNORE,
474 /* codePage */
476 .local_name = "codePage",
477 .type = LDB_MAP_IGNORE,
480 /* dNSHostName */
482 .local_name = "dNSHostName",
483 .type = LDB_MAP_IGNORE,
487 /* dnsDomain */
489 .local_name = "dnsDomain",
490 .type = LDB_MAP_IGNORE,
493 /* dnsRoot */
495 .local_name = "dnsRoot",
496 .type = LDB_MAP_IGNORE,
499 /* countryCode */
501 .local_name = "countryCode",
502 .type = LDB_MAP_IGNORE,
505 /* nTMixedDomain */
507 .local_name = "nTMixedDomain",
508 .type = LDB_MAP_IGNORE,
511 /* operatingSystem */
513 .local_name = "operatingSystem",
514 .type = LDB_MAP_IGNORE,
517 /* operatingSystemVersion */
519 .local_name = "operatingSystemVersion",
520 .type = LDB_MAP_IGNORE,
524 /* servicePrincipalName */
526 .local_name = "servicePrincipalName",
527 .type = LDB_MAP_IGNORE,
530 /* msDS-Behavior-Version */
532 .local_name = "msDS-Behavior-Version",
533 .type = LDB_MAP_IGNORE,
536 /* msDS-KeyVersionNumber */
538 .local_name = "msDS-KeyVersionNumber",
539 .type = LDB_MAP_IGNORE,
542 /* msDs-masteredBy */
544 .local_name = "msDs-masteredBy",
545 .type = LDB_MAP_IGNORE,
548 /* ou */
550 .local_name = "ou",
551 .type = LDB_MAP_KEEP,
554 /* dc */
556 .local_name = "dc",
557 .type = LDB_MAP_KEEP,
560 /* description */
562 .local_name = "description",
563 .type = LDB_MAP_KEEP,
566 /* sambaSID -> objectSid*/
568 .local_name = "objectSid",
569 .type = LDB_MAP_CONVERT,
570 .u = {
571 .convert = {
572 .remote_name = "sambaSID",
573 .convert_local = decode_sid,
574 .convert_remote = encode_sid,
579 /* sambaPwdLastSet -> pwdLastSet */
581 .local_name = "pwdLastSet",
582 .type = LDB_MAP_RENAME,
583 .u = {
584 .rename = {
585 .remote_name = "sambaPwdLastSet",
590 /* accountExpires */
592 .local_name = "accountExpires",
593 .type = LDB_MAP_IGNORE,
596 /* adminCount */
598 .local_name = "adminCount",
599 .type = LDB_MAP_IGNORE,
602 /* canonicalName */
604 .local_name = "canonicalName",
605 .type = LDB_MAP_IGNORE,
608 /* createTimestamp */
610 .local_name = "createTimestamp",
611 .type = LDB_MAP_IGNORE,
614 /* creationTime */
616 .local_name = "creationTime",
617 .type = LDB_MAP_IGNORE,
620 /* dMDLocation */
622 .local_name = "dMDLocation",
623 .type = LDB_MAP_IGNORE,
626 /* fSMORoleOwner */
628 .local_name = "fSMORoleOwner",
629 .type = LDB_MAP_IGNORE,
632 /* forceLogoff */
634 .local_name = "forceLogoff",
635 .type = LDB_MAP_IGNORE,
638 /* instanceType */
640 .local_name = "instanceType",
641 .type = LDB_MAP_IGNORE,
644 /* invocationId */
646 .local_name = "invocationId",
647 .type = LDB_MAP_IGNORE,
650 /* isCriticalSystemObject */
652 .local_name = "isCriticalSystemObject",
653 .type = LDB_MAP_IGNORE,
656 /* localPolicyFlags */
658 .local_name = "localPolicyFlags",
659 .type = LDB_MAP_IGNORE,
662 /* lockOutObservationWindow */
664 .local_name = "lockOutObservationWindow",
665 .type = LDB_MAP_IGNORE,
668 /* lockoutDuration */
670 .local_name = "lockoutDuration",
671 .type = LDB_MAP_IGNORE,
674 /* lockoutThreshold */
676 .local_name = "lockoutThreshold",
677 .type = LDB_MAP_IGNORE,
680 /* logonCount */
682 .local_name = "logonCount",
683 .type = LDB_MAP_IGNORE,
686 /* masteredBy */
688 .local_name = "masteredBy",
689 .type = LDB_MAP_IGNORE,
692 /* maxPwdAge */
694 .local_name = "maxPwdAge",
695 .type = LDB_MAP_IGNORE,
698 /* member */
700 .local_name = "member",
701 .type = LDB_MAP_IGNORE,
704 /* memberOf */
706 .local_name = "memberOf",
707 .type = LDB_MAP_IGNORE,
710 /* minPwdAge */
712 .local_name = "minPwdAge",
713 .type = LDB_MAP_IGNORE,
716 /* minPwdLength */
718 .local_name = "minPwdLength",
719 .type = LDB_MAP_IGNORE,
722 /* modifiedCount */
724 .local_name = "modifiedCount",
725 .type = LDB_MAP_IGNORE,
728 /* modifiedCountAtLastProm */
730 .local_name = "modifiedCountAtLastProm",
731 .type = LDB_MAP_IGNORE,
734 /* modifyTimestamp */
736 .local_name = "modifyTimestamp",
737 .type = LDB_MAP_IGNORE,
740 /* nCName */
742 .local_name = "nCName",
743 .type = LDB_MAP_IGNORE,
746 /* nETBIOSName */
748 .local_name = "nETBIOSName",
749 .type = LDB_MAP_IGNORE,
752 /* oEMInformation */
754 .local_name = "oEMInformation",
755 .type = LDB_MAP_IGNORE,
758 /* privilege */
760 .local_name = "privilege",
761 .type = LDB_MAP_IGNORE,
764 /* pwdHistoryLength */
766 .local_name = "pwdHistoryLength",
767 .type = LDB_MAP_IGNORE,
770 /* pwdProperties */
772 .local_name = "pwdProperties",
773 .type = LDB_MAP_IGNORE,
776 /* rIDAvailablePool */
778 .local_name = "rIDAvailablePool",
779 .type = LDB_MAP_IGNORE,
782 /* revision */
784 .local_name = "revision",
785 .type = LDB_MAP_IGNORE,
788 /* ridManagerReference */
790 .local_name = "ridManagerReference",
791 .type = LDB_MAP_IGNORE,
794 /* sAMAccountType */
796 .local_name = "sAMAccountType",
797 .type = LDB_MAP_IGNORE,
800 /* sPNMappings */
802 .local_name = "sPNMappings",
803 .type = LDB_MAP_IGNORE,
806 /* serverReference */
808 .local_name = "serverReference",
809 .type = LDB_MAP_IGNORE,
812 /* serverState */
814 .local_name = "serverState",
815 .type = LDB_MAP_IGNORE,
818 /* showInAdvancedViewOnly */
820 .local_name = "showInAdvancedViewOnly",
821 .type = LDB_MAP_IGNORE,
824 /* subRefs */
826 .local_name = "subRefs",
827 .type = LDB_MAP_IGNORE,
830 /* systemFlags */
832 .local_name = "systemFlags",
833 .type = LDB_MAP_IGNORE,
836 /* uASCompat */
838 .local_name = "uASCompat",
839 .type = LDB_MAP_IGNORE,
842 /* uSNChanged */
844 .local_name = "uSNChanged",
845 .type = LDB_MAP_IGNORE,
848 /* uSNCreated */
850 .local_name = "uSNCreated",
851 .type = LDB_MAP_IGNORE,
854 /* userPassword */
856 .local_name = "userPassword",
857 .type = LDB_MAP_IGNORE,
860 /* userAccountControl */
862 .local_name = "userAccountControl",
863 .type = LDB_MAP_IGNORE,
866 /* whenChanged */
868 .local_name = "whenChanged",
869 .type = LDB_MAP_IGNORE,
872 /* whenCreated */
874 .local_name = "whenCreated",
875 .type = LDB_MAP_IGNORE,
878 /* uidNumber */
880 .local_name = "unixName",
881 .type = LDB_MAP_CONVERT,
882 .u = {
883 .convert = {
884 .remote_name = "uidNumber",
885 .convert_local = lookup_uid,
890 /* gidNumber. Perhaps make into generate so we can distinguish between
891 * groups and accounts? */
893 .local_name = "unixName",
894 .type = LDB_MAP_CONVERT,
895 .u = {
896 .convert = {
897 .remote_name = "gidNumber",
898 .convert_local = lookup_gid,
903 /* homeDirectory */
905 .local_name = "unixName",
906 .type = LDB_MAP_CONVERT,
907 .u = {
908 .convert = {
909 .remote_name = "homeDirectory",
910 .convert_local = lookup_homedir,
915 .local_name = NULL,
919 /* the context init function */
920 static int samba3sam_init(struct ldb_module *module)
922 int ret;
924 ret = ldb_map_init(module, samba3_attributes, samba3_objectclasses, NULL, NULL, "samba3sam");
925 if (ret != LDB_SUCCESS)
926 return ret;
928 return ldb_next_init(module);
931 static const struct ldb_module_ops ldb_samba3sam_module_ops = {
932 LDB_MAP_OPS
933 .name = "samba3sam",
934 .init_context = samba3sam_init,
937 int ldb_samba3sam_module_init(const char *version)
939 LDB_MODULE_CHECK_VERSION(version);
940 return ldb_register_module(&ldb_samba3sam_module_ops);