s3: Remove close_fn from idmap_methods
[Samba.git] / source3 / libnet / libnet_dssync_passdb.c
blobd38146ed489434713c4cb6b255d82a54b406acf1
1 /*
2 Unix SMB/CIFS implementation.
4 Copyright (C) Guenther Deschner <gd@samba.org> 2008
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "libnet/libnet_dssync.h"
22 #include "libnet/libnet_samsync.h"
23 #include "../libcli/security/security.h"
24 #include "../libds/common/flags.h"
25 #include "../librpc/gen_ndr/ndr_drsuapi.h"
26 #include "dbwrap.h"
27 #include "../libds/common/flag_mapping.h"
29 /****************************************************************
30 ****************************************************************/
32 struct dssync_passdb {
33 struct pdb_methods *methods;
34 struct db_context *all;
35 struct db_context *aliases;
36 struct db_context *groups;
39 struct dssync_passdb_obj {
40 struct dssync_passdb_obj *self;
41 uint32_t type;
42 struct drsuapi_DsReplicaObjectListItemEx *cur;
43 TDB_DATA key;
44 TDB_DATA data;
45 struct db_context *members;
48 struct dssync_passdb_mem {
49 struct dssync_passdb_mem *self;
50 bool active;
51 struct drsuapi_DsReplicaObjectIdentifier3 *cur;
52 struct dssync_passdb_obj *obj;
53 TDB_DATA key;
54 TDB_DATA data;
57 static NTSTATUS dssync_insert_obj(struct dssync_passdb *pctx,
58 struct db_context *db,
59 struct dssync_passdb_obj *obj)
61 NTSTATUS status;
62 struct db_record *rec;
64 rec = db->fetch_locked(db, talloc_tos(), obj->key);
65 if (rec == NULL) {
66 return NT_STATUS_NO_MEMORY;
68 if (rec->value.dsize != 0) {
69 abort();
72 status = rec->store(rec, obj->data, TDB_INSERT);
73 if (!NT_STATUS_IS_OK(status)) {
74 TALLOC_FREE(rec);
75 return status;
77 TALLOC_FREE(rec);
78 return NT_STATUS_OK;
81 static struct dssync_passdb_obj *dssync_parse_obj(const TDB_DATA data)
83 struct dssync_passdb_obj *obj;
85 if (data.dsize != sizeof(obj)) {
86 return NULL;
90 * we need to copy the pointer to avoid alignment problems
91 * on some systems.
93 memcpy(&obj, data.dptr, sizeof(obj));
95 return talloc_get_type_abort(obj, struct dssync_passdb_obj);
98 static struct dssync_passdb_obj *dssync_search_obj_by_guid(struct dssync_passdb *pctx,
99 struct db_context *db,
100 const struct GUID *guid)
102 struct dssync_passdb_obj *obj;
103 int ret;
104 TDB_DATA key;
105 TDB_DATA data;
107 key = make_tdb_data((const uint8_t *)(void *)guid,
108 sizeof(*guid));
110 ret = db->fetch(db, talloc_tos(), key, &data);
111 if (ret != 0) {
112 return NULL;
115 obj = dssync_parse_obj(data);
116 return obj;
119 static NTSTATUS dssync_create_obj(struct dssync_passdb *pctx,
120 struct db_context *db,
121 uint32_t type,
122 struct drsuapi_DsReplicaObjectListItemEx *cur,
123 struct dssync_passdb_obj **_obj)
125 NTSTATUS status;
126 struct dssync_passdb_obj *obj;
128 obj = talloc_zero(pctx, struct dssync_passdb_obj);
129 if (obj == NULL) {
130 return NT_STATUS_NO_MEMORY;
132 obj->self = obj;
133 obj->cur = cur;
134 obj->type = type;
135 obj->key = make_tdb_data((const uint8_t *)(void *)&cur->object.identifier->guid,
136 sizeof(cur->object.identifier->guid));
137 obj->data = make_tdb_data((const uint8_t *)(void *)&obj->self,
138 sizeof(obj->self));
140 obj->members = db_open_rbt(obj);
141 if (obj->members == NULL) {
142 return NT_STATUS_NO_MEMORY;
145 status = dssync_insert_obj(pctx, db, obj);
146 if (!NT_STATUS_IS_OK(status)) {
147 TALLOC_FREE(obj);
148 return status;
150 *_obj = obj;
151 return NT_STATUS_OK;
154 static NTSTATUS dssync_insert_mem(struct dssync_passdb *pctx,
155 struct dssync_passdb_obj *obj,
156 struct dssync_passdb_mem *mem)
158 NTSTATUS status;
159 struct db_record *rec;
161 rec = obj->members->fetch_locked(obj->members, talloc_tos(), mem->key);
162 if (rec == NULL) {
163 return NT_STATUS_NO_MEMORY;
165 if (rec->value.dsize != 0) {
166 abort();
169 status = rec->store(rec, mem->data, TDB_INSERT);
170 if (!NT_STATUS_IS_OK(status)) {
171 TALLOC_FREE(rec);
172 return status;
174 TALLOC_FREE(rec);
175 return NT_STATUS_OK;
178 static NTSTATUS dssync_create_mem(struct dssync_passdb *pctx,
179 struct dssync_passdb_obj *obj,
180 bool active,
181 struct drsuapi_DsReplicaObjectIdentifier3 *cur,
182 struct dssync_passdb_mem **_mem)
184 NTSTATUS status;
185 struct dssync_passdb_mem *mem;
187 mem = talloc_zero(pctx, struct dssync_passdb_mem);
188 if (mem == NULL) {
189 return NT_STATUS_NO_MEMORY;
191 mem->self = mem;
192 mem->cur = cur;
193 mem->active = active;
194 mem->obj = NULL;
195 mem->key = make_tdb_data((const uint8_t *)(void *)&cur->guid,
196 sizeof(cur->guid));
197 mem->data = make_tdb_data((const uint8_t *)(void *)&mem->self,
198 sizeof(mem->self));
200 status = dssync_insert_mem(pctx, obj, mem);
201 if (!NT_STATUS_IS_OK(status)) {
202 TALLOC_FREE(obj);
203 return status;
205 *_mem = mem;
206 return NT_STATUS_OK;
209 static struct dssync_passdb_mem *dssync_parse_mem(const TDB_DATA data)
211 struct dssync_passdb_mem *mem;
213 if (data.dsize != sizeof(mem)) {
214 return NULL;
218 * we need to copy the pointer to avoid alignment problems
219 * on some systems.
221 memcpy(&mem, data.dptr, sizeof(mem));
223 return talloc_get_type_abort(mem, struct dssync_passdb_mem);
226 static NTSTATUS passdb_startup(struct dssync_context *ctx, TALLOC_CTX *mem_ctx,
227 struct replUpToDateVectorBlob **pold_utdv)
229 NTSTATUS status;
230 struct dssync_passdb *pctx;
232 pctx = talloc_zero(mem_ctx, struct dssync_passdb);
233 if (pctx == NULL) {
234 return NT_STATUS_NO_MEMORY;
237 if (ctx->output_filename) {
238 status = make_pdb_method_name(&pctx->methods, ctx->output_filename);
239 } else {
240 status = make_pdb_method_name(&pctx->methods, lp_passdb_backend());
243 if (!NT_STATUS_IS_OK(status)) {
244 return status;
247 pctx->all = db_open_rbt(pctx);
248 if (pctx->all == NULL) {
249 return NT_STATUS_NO_MEMORY;
251 pctx->aliases = db_open_rbt(pctx);
252 if (pctx->aliases == NULL) {
253 return NT_STATUS_NO_MEMORY;
255 pctx->groups = db_open_rbt(pctx);
256 if (pctx->groups == NULL) {
257 return NT_STATUS_NO_MEMORY;
260 ctx->private_data = pctx;
262 return status;
265 /****************************************************************
266 ****************************************************************/
268 struct dssync_passdb_traverse_amembers {
269 struct dssync_context *ctx;
270 struct dssync_passdb_obj *obj;
271 const char *name;
272 uint32_t idx;
275 struct dssync_passdb_traverse_aliases {
276 struct dssync_context *ctx;
277 const char *name;
278 uint32_t idx;
281 static int dssync_passdb_traverse_amembers(struct db_record *rec,
282 void *private_data)
284 struct dssync_passdb_traverse_amembers *state =
285 (struct dssync_passdb_traverse_amembers *)private_data;
286 struct dssync_passdb *pctx =
287 talloc_get_type_abort(state->ctx->private_data,
288 struct dssync_passdb);
289 struct dssync_passdb_mem *mem;
290 NTSTATUS status;
291 struct dom_sid alias_sid;
292 struct dom_sid member_sid;
293 const char *member_dn;
294 size_t num_members;
295 size_t i;
296 struct dom_sid *members;
297 bool is_member = false;
298 const char *action;
300 state->idx++;
302 alias_sid = state->obj->cur->object.identifier->sid;
304 mem = dssync_parse_mem(rec->value);
305 if (mem == NULL) {
306 return -1;
309 member_sid = mem->cur->sid;
310 member_dn = mem->cur->dn;
312 mem->obj = dssync_search_obj_by_guid(pctx, pctx->all, &mem->cur->guid);
313 if (mem->obj == NULL) {
314 DEBUG(0,("alias[%s] member[%s] can't resolve member - ignoring\n",
315 sid_string_dbg(&alias_sid),
316 is_null_sid(&member_sid)?
317 sid_string_dbg(&member_sid):
318 member_dn));
319 return 0;
322 switch (mem->obj->type) {
323 case ATYPE_DISTRIBUTION_LOCAL_GROUP:
324 case ATYPE_DISTRIBUTION_GLOBAL_GROUP:
325 DEBUG(0, ("alias[%s] ignore distribution group [%s]\n",
326 sid_string_dbg(&alias_sid),
327 member_dn));
328 return 0;
329 default:
330 break;
333 DEBUG(0,("alias[%s] member[%s]\n",
334 sid_string_dbg(&alias_sid),
335 sid_string_dbg(&member_sid)));
337 status = pdb_enum_aliasmem(&alias_sid, talloc_tos(),
338 &members, &num_members);
339 if (!NT_STATUS_IS_OK(status)) {
340 DEBUG(0, ("Could not find current alias members %s - %s\n",
341 sid_string_dbg(&alias_sid),
342 nt_errstr(status)));
343 return -1;
346 for (i=0; i < num_members; i++) {
347 bool match;
349 match = dom_sid_equal(&members[i], &member_sid);
350 if (match) {
351 is_member = true;
352 break;
356 status = NT_STATUS_OK;
357 action = "none";
358 if (!is_member && mem->active) {
359 action = "add";
360 pdb_add_aliasmem(&alias_sid, &member_sid);
361 } else if (is_member && !mem->active) {
362 action = "delete";
363 pdb_del_aliasmem(&alias_sid, &member_sid);
365 if (!NT_STATUS_IS_OK(status)) {
366 DEBUG(0, ("Could not %s %s as alias members of %s - %s\n",
367 action,
368 sid_string_dbg(&member_sid),
369 sid_string_dbg(&alias_sid),
370 nt_errstr(status)));
371 return -1;
374 return 0;
377 static int dssync_passdb_traverse_aliases(struct db_record *rec,
378 void *private_data)
380 struct dssync_passdb_traverse_aliases *state =
381 (struct dssync_passdb_traverse_aliases *)private_data;
382 struct dssync_passdb *pctx =
383 talloc_get_type_abort(state->ctx->private_data,
384 struct dssync_passdb);
385 struct dssync_passdb_traverse_amembers mstate;
386 struct dssync_passdb_obj *obj;
387 int ret;
389 state->idx++;
390 if (pctx->methods == NULL) {
391 return -1;
394 obj = dssync_parse_obj(rec->value);
395 if (obj == NULL) {
396 return -1;
399 ZERO_STRUCT(mstate);
400 mstate.ctx = state->ctx;
401 mstate.name = "members";
402 mstate.obj = obj;
403 ret = obj->members->traverse_read(obj->members,
404 dssync_passdb_traverse_amembers,
405 &mstate);
406 if (ret < 0) {
407 return -1;
410 return 0;
413 struct dssync_passdb_traverse_gmembers {
414 struct dssync_context *ctx;
415 struct dssync_passdb_obj *obj;
416 const char *name;
417 uint32_t idx;
420 struct dssync_passdb_traverse_groups {
421 struct dssync_context *ctx;
422 const char *name;
423 uint32_t idx;
426 static int dssync_passdb_traverse_gmembers(struct db_record *rec,
427 void *private_data)
429 struct dssync_passdb_traverse_gmembers *state =
430 (struct dssync_passdb_traverse_gmembers *)private_data;
431 struct dssync_passdb *pctx =
432 talloc_get_type_abort(state->ctx->private_data,
433 struct dssync_passdb);
434 struct dssync_passdb_mem *mem;
435 NTSTATUS status;
436 char *nt_member = NULL;
437 char **unix_members;
438 struct dom_sid group_sid;
439 struct dom_sid member_sid;
440 struct samu *member = NULL;
441 const char *member_dn = NULL;
442 GROUP_MAP map;
443 struct group *grp;
444 uint32_t rid;
445 bool is_unix_member = false;
447 state->idx++;
449 group_sid = state->obj->cur->object.identifier->sid;
451 status = dom_sid_split_rid(talloc_tos(), &group_sid, NULL, &rid);
452 if (!NT_STATUS_IS_OK(status)) {
453 return -1;
456 mem = dssync_parse_mem(rec->value);
457 if (mem == NULL) {
458 return -1;
461 member_sid = mem->cur->sid;
462 member_dn = mem->cur->dn;
464 mem->obj = dssync_search_obj_by_guid(pctx, pctx->all, &mem->cur->guid);
465 if (mem->obj == NULL) {
466 DEBUG(0,("group[%s] member[%s] can't resolve member - ignoring\n",
467 sid_string_dbg(&group_sid),
468 is_null_sid(&member_sid)?
469 sid_string_dbg(&member_sid):
470 member_dn));
471 return 0;
474 member_sid = mem->obj->cur->object.identifier->sid;
475 member_dn = mem->obj->cur->object.identifier->dn;
477 switch (mem->obj->type) {
478 case ATYPE_SECURITY_LOCAL_GROUP:
479 case ATYPE_SECURITY_GLOBAL_GROUP:
480 DEBUG(0, ("Group[%s] ignore member group [%s]\n",
481 sid_string_dbg(&group_sid),
482 sid_string_dbg(&member_sid)));
483 return 0;
485 case ATYPE_DISTRIBUTION_LOCAL_GROUP:
486 case ATYPE_DISTRIBUTION_GLOBAL_GROUP:
487 DEBUG(0, ("Group[%s] ignore distribution group [%s]\n",
488 sid_string_dbg(&group_sid),
489 member_dn));
490 return 0;
491 default:
492 break;
495 if (!get_domain_group_from_sid(group_sid, &map)) {
496 DEBUG(0, ("Could not find global group %s\n",
497 sid_string_dbg(&group_sid)));
498 //return NT_STATUS_NO_SUCH_GROUP;
499 return -1;
502 if (!(grp = getgrgid(map.gid))) {
503 DEBUG(0, ("Could not find unix group %lu\n", (unsigned long)map.gid));
504 //return NT_STATUS_NO_SUCH_GROUP;
505 return -1;
508 DEBUG(0,("Group members of %s: ", grp->gr_name));
510 if ( !(member = samu_new(talloc_tos())) ) {
511 //return NT_STATUS_NO_MEMORY;
512 return -1;
515 if (!pdb_getsampwsid(member, &member_sid)) {
516 DEBUG(1, ("Found bogus group member: (member_sid=%s group=%s)\n",
517 sid_string_tos(&member_sid), grp->gr_name));
518 TALLOC_FREE(member);
519 return -1;
522 if (pdb_get_group_rid(member) == rid) {
523 DEBUGADD(0,("%s(primary),", pdb_get_username(member)));
524 TALLOC_FREE(member);
525 return -1;
528 DEBUGADD(0,("%s,", pdb_get_username(member)));
529 nt_member = talloc_strdup(talloc_tos(), pdb_get_username(member));
530 TALLOC_FREE(member);
532 DEBUGADD(0,("\n"));
534 unix_members = grp->gr_mem;
536 while (*unix_members) {
537 if (strcmp(*unix_members, nt_member) == 0) {
538 is_unix_member = true;
539 break;
541 unix_members += 1;
544 if (!is_unix_member && mem->active) {
545 smb_add_user_group(grp->gr_name, nt_member);
546 } else if (is_unix_member && !mem->active) {
547 smb_delete_user_group(grp->gr_name, nt_member);
550 return 0;
553 static int dssync_passdb_traverse_groups(struct db_record *rec,
554 void *private_data)
556 struct dssync_passdb_traverse_groups *state =
557 (struct dssync_passdb_traverse_groups *)private_data;
558 struct dssync_passdb *pctx =
559 talloc_get_type_abort(state->ctx->private_data,
560 struct dssync_passdb);
561 struct dssync_passdb_traverse_gmembers mstate;
562 struct dssync_passdb_obj *obj;
563 int ret;
565 state->idx++;
566 if (pctx->methods == NULL) {
567 return -1;
570 obj = dssync_parse_obj(rec->value);
571 if (obj == NULL) {
572 return -1;
575 ZERO_STRUCT(mstate);
576 mstate.ctx = state->ctx;
577 mstate.name = "members";
578 mstate.obj = obj;
579 ret = obj->members->traverse_read(obj->members,
580 dssync_passdb_traverse_gmembers,
581 &mstate);
582 if (ret < 0) {
583 return -1;
586 return 0;
589 static NTSTATUS passdb_finish(struct dssync_context *ctx, TALLOC_CTX *mem_ctx,
590 struct replUpToDateVectorBlob *new_utdv)
592 struct dssync_passdb *pctx =
593 talloc_get_type_abort(ctx->private_data,
594 struct dssync_passdb);
595 struct dssync_passdb_traverse_aliases astate;
596 struct dssync_passdb_traverse_groups gstate;
597 int ret;
599 ZERO_STRUCT(astate);
600 astate.ctx = ctx;
601 astate.name = "aliases";
602 ret = pctx->aliases->traverse_read(pctx->aliases,
603 dssync_passdb_traverse_aliases,
604 &astate);
605 if (ret < 0) {
606 return NT_STATUS_INTERNAL_ERROR;
609 ZERO_STRUCT(gstate);
610 gstate.ctx = ctx;
611 gstate.name = "groups";
612 ret = pctx->groups->traverse_read(pctx->groups,
613 dssync_passdb_traverse_groups,
614 &gstate);
615 if (ret < 0) {
616 return NT_STATUS_INTERNAL_ERROR;
619 TALLOC_FREE(pctx->methods);
620 TALLOC_FREE(pctx);
622 return NT_STATUS_OK;
625 /****************************************************************
626 ****************************************************************/
628 static NTSTATUS smb_create_user(TALLOC_CTX *mem_ctx,
629 uint32_t acct_flags,
630 const char *account,
631 struct passwd **passwd_p)
633 struct passwd *passwd;
634 char *add_script = NULL;
636 passwd = Get_Pwnam_alloc(mem_ctx, account);
637 if (passwd) {
638 *passwd_p = passwd;
639 return NT_STATUS_OK;
642 /* Create appropriate user */
643 if (acct_flags & ACB_NORMAL) {
644 add_script = talloc_strdup(mem_ctx, lp_adduser_script());
645 } else if ( (acct_flags & ACB_WSTRUST) ||
646 (acct_flags & ACB_SVRTRUST) ||
647 (acct_flags & ACB_DOMTRUST) ) {
648 add_script = talloc_strdup(mem_ctx, lp_addmachine_script());
649 } else {
650 DEBUG(1, ("Unknown user type: %s\n",
651 pdb_encode_acct_ctrl(acct_flags, NEW_PW_FORMAT_SPACE_PADDED_LEN)));
652 return NT_STATUS_UNSUCCESSFUL;
655 if (!add_script) {
656 return NT_STATUS_NO_MEMORY;
659 if (*add_script) {
660 int add_ret;
661 add_script = talloc_all_string_sub(mem_ctx, add_script,
662 "%u", account);
663 if (!add_script) {
664 return NT_STATUS_NO_MEMORY;
666 add_ret = smbrun(add_script, NULL);
667 DEBUG(add_ret ? 0 : 1,("fetch_account: Running the command `%s' "
668 "gave %d\n", add_script, add_ret));
669 if (add_ret == 0) {
670 smb_nscd_flush_user_cache();
674 /* try and find the possible unix account again */
675 passwd = Get_Pwnam_alloc(mem_ctx, account);
676 if (!passwd) {
677 return NT_STATUS_NO_SUCH_USER;
680 *passwd_p = passwd;
682 return NT_STATUS_OK;
685 static struct drsuapi_DsReplicaAttribute *find_drsuapi_attr(
686 const struct drsuapi_DsReplicaObjectListItemEx *cur,
687 uint32_t attid)
689 int i = 0;
691 for (i = 0; i < cur->object.attribute_ctr.num_attributes; i++) {
692 struct drsuapi_DsReplicaAttribute *attr;
694 attr = &cur->object.attribute_ctr.attributes[i];
696 if (attr->attid == attid) {
697 return attr;
701 return NULL;
704 static NTSTATUS find_drsuapi_attr_string(TALLOC_CTX *mem_ctx,
705 const struct drsuapi_DsReplicaObjectListItemEx *cur,
706 uint32_t attid,
707 uint32_t *_count,
708 char ***_array)
710 struct drsuapi_DsReplicaAttribute *attr;
711 char **array;
712 uint32_t a;
714 attr = find_drsuapi_attr(cur, attid);
715 if (attr == NULL) {
716 return NT_STATUS_PROPSET_NOT_FOUND;
719 array = talloc_array(mem_ctx, char *, attr->value_ctr.num_values);
720 if (array == NULL) {
721 return NT_STATUS_NO_MEMORY;
724 for (a = 0; a < attr->value_ctr.num_values; a++) {
725 const DATA_BLOB *blob;
726 ssize_t ret;
728 blob = attr->value_ctr.values[a].blob;
730 if (blob == NULL) {
731 return NT_STATUS_INTERNAL_DB_CORRUPTION;
734 ret = pull_string_talloc(array, NULL, 0, &array[a],
735 blob->data, blob->length,
736 STR_UNICODE);
737 if (ret == -1) {
738 //TODO
739 return NT_STATUS_INTERNAL_ERROR;
743 *_count = attr->value_ctr.num_values;
744 *_array = array;
745 return NT_STATUS_OK;
748 static NTSTATUS find_drsuapi_attr_int32(TALLOC_CTX *mem_ctx,
749 const struct drsuapi_DsReplicaObjectListItemEx *cur,
750 uint32_t attid,
751 uint32_t *_count,
752 int32_t **_array)
754 struct drsuapi_DsReplicaAttribute *attr;
755 int32_t *array;
756 uint32_t a;
758 attr = find_drsuapi_attr(cur, attid);
759 if (attr == NULL) {
760 return NT_STATUS_PROPSET_NOT_FOUND;
763 array = talloc_array(mem_ctx, int32_t, attr->value_ctr.num_values);
764 if (array == NULL) {
765 return NT_STATUS_NO_MEMORY;
768 for (a = 0; a < attr->value_ctr.num_values; a++) {
769 const DATA_BLOB *blob;
771 blob = attr->value_ctr.values[a].blob;
773 if (blob == NULL) {
774 return NT_STATUS_INTERNAL_DB_CORRUPTION;
777 if (blob->length != 4) {
778 return NT_STATUS_INTERNAL_DB_CORRUPTION;
781 array[a] = IVAL(blob->data, 0);
784 *_count = attr->value_ctr.num_values;
785 *_array = array;
786 return NT_STATUS_OK;
789 static NTSTATUS find_drsuapi_attr_blob(TALLOC_CTX *mem_ctx,
790 const struct drsuapi_DsReplicaObjectListItemEx *cur,
791 uint32_t attid,
792 uint32_t *_count,
793 DATA_BLOB **_array)
795 struct drsuapi_DsReplicaAttribute *attr;
796 DATA_BLOB *array;
797 uint32_t a;
799 attr = find_drsuapi_attr(cur, attid);
800 if (attr == NULL) {
801 return NT_STATUS_PROPSET_NOT_FOUND;
804 array = talloc_array(mem_ctx, DATA_BLOB, attr->value_ctr.num_values);
805 if (array == NULL) {
806 return NT_STATUS_NO_MEMORY;
809 for (a = 0; a < attr->value_ctr.num_values; a++) {
810 const DATA_BLOB *blob;
812 blob = attr->value_ctr.values[a].blob;
814 if (blob == NULL) {
815 return NT_STATUS_INTERNAL_DB_CORRUPTION;
818 array[a] = data_blob_talloc(array, blob->data, blob->length);
819 if (array[a].length != blob->length) {
820 return NT_STATUS_NO_MEMORY;
823 *_count = attr->value_ctr.num_values;
824 *_array = array;
825 return NT_STATUS_OK;
828 static NTSTATUS find_drsuapi_attr_int64(TALLOC_CTX *mem_ctx,
829 const struct drsuapi_DsReplicaObjectListItemEx *cur,
830 uint32_t attid,
831 uint32_t *_count,
832 int64_t **_array)
834 struct drsuapi_DsReplicaAttribute *attr;
835 int64_t *array;
836 uint32_t a;
838 attr = find_drsuapi_attr(cur, attid);
839 if (attr == NULL) {
840 return NT_STATUS_PROPSET_NOT_FOUND;
843 array = talloc_array(mem_ctx, int64_t, attr->value_ctr.num_values);
844 if (array == NULL) {
845 return NT_STATUS_NO_MEMORY;
848 for (a = 0; a < attr->value_ctr.num_values; a++) {
849 const DATA_BLOB *blob;
851 blob = attr->value_ctr.values[a].blob;
853 if (blob == NULL) {
854 return NT_STATUS_INTERNAL_DB_CORRUPTION;
857 if (blob->length != 8) {
858 return NT_STATUS_INTERNAL_DB_CORRUPTION;
861 array[a] = BVAL(blob->data, 0);
863 *_count = attr->value_ctr.num_values;
864 *_array = array;
865 return NT_STATUS_OK;
868 static NTSTATUS find_drsuapi_attr_dn(TALLOC_CTX *mem_ctx,
869 const struct drsuapi_DsReplicaObjectListItemEx *cur,
870 uint32_t attid,
871 uint32_t *_count,
872 struct drsuapi_DsReplicaObjectIdentifier3 **_array)
874 struct drsuapi_DsReplicaAttribute *attr;
875 struct drsuapi_DsReplicaObjectIdentifier3 *array;
876 uint32_t a;
878 attr = find_drsuapi_attr(cur, attid);
879 if (attr == NULL) {
880 return NT_STATUS_PROPSET_NOT_FOUND;
883 array = talloc_array(mem_ctx,
884 struct drsuapi_DsReplicaObjectIdentifier3,
885 attr->value_ctr.num_values);
886 if (array == NULL) {
887 return NT_STATUS_NO_MEMORY;
890 for (a = 0; a < attr->value_ctr.num_values; a++) {
891 const DATA_BLOB *blob;
892 enum ndr_err_code ndr_err;
893 NTSTATUS status;
895 blob = attr->value_ctr.values[a].blob;
897 if (blob == NULL) {
898 return NT_STATUS_INTERNAL_DB_CORRUPTION;
901 /* windows sometimes sends an extra two pad bytes here */
902 ndr_err = ndr_pull_struct_blob(blob, array, &array[a],
903 (ndr_pull_flags_fn_t)ndr_pull_drsuapi_DsReplicaObjectIdentifier3);
904 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
905 status = ndr_map_error2ntstatus(ndr_err);
906 return status;
909 *_count = attr->value_ctr.num_values;
910 *_array = array;
911 return NT_STATUS_OK;
914 #define GET_BLOB_EX(attr, needed) do { \
915 NTSTATUS _status; \
916 uint32_t _cnt; \
917 DATA_BLOB *_vals = NULL; \
918 attr = data_blob_null; \
919 _status = find_drsuapi_attr_blob(mem_ctx, cur, \
920 DRSUAPI_ATTID_ ## attr, \
921 &_cnt, &_vals); \
922 if (NT_STATUS_EQUAL(_status, NT_STATUS_PROPSET_NOT_FOUND)) { \
923 if (!needed) { \
924 _status = NT_STATUS_OK; \
925 _cnt = 0; \
928 if (!NT_STATUS_IS_OK(_status)) { \
929 DEBUG(0,(__location__ "attr[%s] %s\n", \
930 #attr, nt_errstr(_status))); \
931 return _status; \
933 if (_cnt == 0) { \
934 if (needed) { \
935 talloc_free(_vals); \
936 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
937 return NT_STATUS_OBJECT_NAME_NOT_FOUND; \
939 } else if (_cnt > 1) { \
940 talloc_free(_vals); \
941 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
942 return NT_STATUS_INTERNAL_DB_CORRUPTION; \
943 } else { \
944 attr = _vals[0]; \
945 (void)talloc_steal(mem_ctx, _vals[0].data); \
947 talloc_free(_vals); \
948 } while(0)
950 #define GET_STRING_EX(attr, needed) do { \
951 NTSTATUS _status; \
952 uint32_t _cnt; \
953 char **_vals = NULL; \
954 attr = NULL; \
955 _status = find_drsuapi_attr_string(mem_ctx, cur, \
956 DRSUAPI_ATTID_ ## attr, \
957 &_cnt, &_vals); \
958 if (NT_STATUS_EQUAL(_status, NT_STATUS_PROPSET_NOT_FOUND)) { \
959 if (!needed) { \
960 _status = NT_STATUS_OK; \
961 _cnt = 0; \
964 if (!NT_STATUS_IS_OK(_status)) { \
965 DEBUG(0,(__location__ "attr[%s] %s\n", \
966 #attr, nt_errstr(_status))); \
967 return _status; \
969 if (_cnt == 0) { \
970 if (needed) { \
971 talloc_free(_vals); \
972 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
973 return NT_STATUS_OBJECT_NAME_NOT_FOUND; \
975 } else if (_cnt > 1) { \
976 talloc_free(_vals); \
977 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
978 return NT_STATUS_INTERNAL_DB_CORRUPTION; \
979 } else { \
980 attr = talloc_move(mem_ctx, &_vals[0]); \
982 talloc_free(_vals); \
983 } while(0)
985 #define GET_UINT32_EX(attr, needed) do { \
986 NTSTATUS _status; \
987 uint32_t _cnt; \
988 int32_t*_vals = NULL; \
989 attr = 0; \
990 _status = find_drsuapi_attr_int32(mem_ctx, cur, \
991 DRSUAPI_ATTID_ ## attr, \
992 &_cnt, &_vals); \
993 if (NT_STATUS_EQUAL(_status, NT_STATUS_PROPSET_NOT_FOUND)) { \
994 if (!needed) { \
995 _status = NT_STATUS_OK; \
996 _cnt = 0; \
999 if (!NT_STATUS_IS_OK(_status)) { \
1000 DEBUG(0,(__location__ "attr[%s] %s\n", \
1001 #attr, nt_errstr(_status))); \
1002 return _status; \
1004 if (_cnt == 0) { \
1005 if (needed) { \
1006 talloc_free(_vals); \
1007 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1008 return NT_STATUS_OBJECT_NAME_NOT_FOUND; \
1010 } else if (_cnt > 1) { \
1011 talloc_free(_vals); \
1012 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1013 return NT_STATUS_INTERNAL_DB_CORRUPTION; \
1014 } else { \
1015 attr = (uint32_t)_vals[0]; \
1017 talloc_free(_vals); \
1018 } while(0)
1020 #define GET_UINT64_EX(attr, needed) do { \
1021 NTSTATUS _status; \
1022 uint32_t _cnt; \
1023 int64_t *_vals = NULL; \
1024 attr = 0; \
1025 _status = find_drsuapi_attr_int64(mem_ctx, cur, \
1026 DRSUAPI_ATTID_ ## attr, \
1027 &_cnt, &_vals); \
1028 if (NT_STATUS_EQUAL(_status, NT_STATUS_PROPSET_NOT_FOUND)) { \
1029 if (!needed) { \
1030 _status = NT_STATUS_OK; \
1031 _cnt = 0; \
1034 if (!NT_STATUS_IS_OK(_status)) { \
1035 DEBUG(0,(__location__ "attr[%s] %s\n", \
1036 #attr, nt_errstr(_status))); \
1037 return _status; \
1039 if (_cnt == 0) { \
1040 if (needed) { \
1041 talloc_free(_vals); \
1042 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1043 return NT_STATUS_OBJECT_NAME_NOT_FOUND; \
1045 } else if (_cnt > 1) { \
1046 talloc_free(_vals); \
1047 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1048 return NT_STATUS_INTERNAL_DB_CORRUPTION; \
1049 } else { \
1050 attr = (uint64_t)_vals[0]; \
1052 talloc_free(_vals); \
1053 } while(0)
1055 #define GET_BLOB(attr) GET_BLOB_EX(attr, false)
1056 #define GET_STRING(attr) GET_STRING_EX(attr, false)
1057 #define GET_UINT32(attr) GET_UINT32_EX(attr, false)
1058 #define GET_UINT64(attr) GET_UINT64_EX(attr, false)
1060 /* Convert a struct samu_DELTA to a struct samu. */
1061 #define STRING_CHANGED (old_string && !new_string) ||\
1062 (!old_string && new_string) ||\
1063 (old_string && new_string && (strcmp(old_string, new_string) != 0))
1065 #define STRING_CHANGED_NC(s1,s2) ((s1) && !(s2)) ||\
1066 (!(s1) && (s2)) ||\
1067 ((s1) && (s2) && (strcmp((s1), (s2)) != 0))
1069 /****************************************************************
1070 ****************************************************************/
1072 static NTSTATUS sam_account_from_object(struct samu *account,
1073 struct drsuapi_DsReplicaObjectListItemEx *cur)
1075 TALLOC_CTX *mem_ctx = account;
1076 const char *old_string, *new_string;
1077 time_t unix_time, stored_time;
1078 uchar zero_buf[16];
1079 NTSTATUS status;
1081 NTTIME lastLogon;
1082 NTTIME lastLogoff;
1083 NTTIME pwdLastSet;
1084 NTTIME accountExpires;
1085 const char *sAMAccountName;
1086 const char *displayName;
1087 const char *homeDirectory;
1088 const char *homeDrive;
1089 const char *scriptPath;
1090 const char *profilePath;
1091 const char *description;
1092 const char *userWorkstations;
1093 const char *comment;
1094 DATA_BLOB userParameters;
1095 struct dom_sid objectSid;
1096 uint32_t primaryGroupID;
1097 uint32_t userAccountControl;
1098 DATA_BLOB logonHours;
1099 uint32_t badPwdCount;
1100 uint32_t logonCount;
1101 DATA_BLOB unicodePwd;
1102 DATA_BLOB dBCSPwd;
1104 uint32_t rid = 0;
1105 uint32_t acct_flags;
1106 uint32_t units_per_week;
1108 memset(zero_buf, '\0', sizeof(zero_buf));
1110 objectSid = cur->object.identifier->sid;
1111 GET_STRING_EX(sAMAccountName, true);
1112 DEBUG(0,("sam_account_from_object(%s, %s) start\n",
1113 sAMAccountName, sid_string_dbg(&objectSid)));
1114 GET_UINT64(lastLogon);
1115 GET_UINT64(lastLogoff);
1116 GET_UINT64(pwdLastSet);
1117 GET_UINT64(accountExpires);
1118 GET_STRING(displayName);
1119 GET_STRING(homeDirectory);
1120 GET_STRING(homeDrive);
1121 GET_STRING(scriptPath);
1122 GET_STRING(profilePath);
1123 GET_STRING(description);
1124 GET_STRING(userWorkstations);
1125 GET_STRING(comment);
1126 GET_BLOB(userParameters);
1127 GET_UINT32(primaryGroupID);
1128 GET_UINT32(userAccountControl);
1129 GET_BLOB(logonHours);
1130 GET_UINT32(badPwdCount);
1131 GET_UINT32(logonCount);
1132 GET_BLOB(unicodePwd);
1133 GET_BLOB(dBCSPwd);
1135 status = dom_sid_split_rid(mem_ctx, &objectSid, NULL, &rid);
1136 if (!NT_STATUS_IS_OK(status)) {
1137 return status;
1139 acct_flags = ds_uf2acb(userAccountControl);
1141 /* Username, fullname, home dir, dir drive, logon script, acct
1142 desc, workstations, profile. */
1144 if (sAMAccountName) {
1145 old_string = pdb_get_nt_username(account);
1146 new_string = sAMAccountName;
1148 if (STRING_CHANGED) {
1149 pdb_set_nt_username(account, new_string, PDB_CHANGED);
1152 /* Unix username is the same - for sanity */
1153 old_string = pdb_get_username( account );
1154 if (STRING_CHANGED) {
1155 pdb_set_username(account, new_string, PDB_CHANGED);
1159 if (displayName) {
1160 old_string = pdb_get_fullname(account);
1161 new_string = displayName;
1163 if (STRING_CHANGED)
1164 pdb_set_fullname(account, new_string, PDB_CHANGED);
1167 if (homeDirectory) {
1168 old_string = pdb_get_homedir(account);
1169 new_string = homeDirectory;
1171 if (STRING_CHANGED)
1172 pdb_set_homedir(account, new_string, PDB_CHANGED);
1175 if (homeDrive) {
1176 old_string = pdb_get_dir_drive(account);
1177 new_string = homeDrive;
1179 if (STRING_CHANGED)
1180 pdb_set_dir_drive(account, new_string, PDB_CHANGED);
1183 if (scriptPath) {
1184 old_string = pdb_get_logon_script(account);
1185 new_string = scriptPath;
1187 if (STRING_CHANGED)
1188 pdb_set_logon_script(account, new_string, PDB_CHANGED);
1191 if (description) {
1192 old_string = pdb_get_acct_desc(account);
1193 new_string = description;
1195 if (STRING_CHANGED)
1196 pdb_set_acct_desc(account, new_string, PDB_CHANGED);
1199 if (userWorkstations) {
1200 old_string = pdb_get_workstations(account);
1201 new_string = userWorkstations;
1203 if (STRING_CHANGED)
1204 pdb_set_workstations(account, new_string, PDB_CHANGED);
1207 if (profilePath) {
1208 old_string = pdb_get_profile_path(account);
1209 new_string = profilePath;
1211 if (STRING_CHANGED)
1212 pdb_set_profile_path(account, new_string, PDB_CHANGED);
1215 if (userParameters.data) {
1216 char *newstr;
1217 old_string = pdb_get_munged_dial(account);
1218 newstr = (userParameters.length == 0) ? NULL :
1219 base64_encode_data_blob(talloc_tos(), userParameters);
1221 if (STRING_CHANGED_NC(old_string, newstr))
1222 pdb_set_munged_dial(account, newstr, PDB_CHANGED);
1223 TALLOC_FREE(newstr);
1226 /* User and group sid */
1227 if (rid != 0 && pdb_get_user_rid(account) != rid) {
1228 pdb_set_user_sid_from_rid(account, rid, PDB_CHANGED);
1230 if (primaryGroupID != 0 && pdb_get_group_rid(account) != primaryGroupID) {
1231 pdb_set_group_sid_from_rid(account, primaryGroupID, PDB_CHANGED);
1234 /* Logon and password information */
1235 if (!nt_time_is_zero(&lastLogon)) {
1236 unix_time = nt_time_to_unix(lastLogon);
1237 stored_time = pdb_get_logon_time(account);
1238 if (stored_time != unix_time)
1239 pdb_set_logon_time(account, unix_time, PDB_CHANGED);
1242 if (!nt_time_is_zero(&lastLogoff)) {
1243 unix_time = nt_time_to_unix(lastLogoff);
1244 stored_time = pdb_get_logoff_time(account);
1245 if (stored_time != unix_time)
1246 pdb_set_logoff_time(account, unix_time,PDB_CHANGED);
1249 /* Logon Divs */
1250 units_per_week = logonHours.length * 8;
1252 if (pdb_get_logon_divs(account) != units_per_week) {
1253 pdb_set_logon_divs(account, units_per_week, PDB_CHANGED);
1256 /* Logon Hours Len */
1257 if (units_per_week/8 != pdb_get_hours_len(account)) {
1258 pdb_set_hours_len(account, units_per_week/8, PDB_CHANGED);
1261 /* Logon Hours */
1262 if (logonHours.data) {
1263 char oldstr[44], newstr[44];
1264 pdb_sethexhours(oldstr, pdb_get_hours(account));
1265 pdb_sethexhours(newstr, logonHours.data);
1266 if (!strequal(oldstr, newstr)) {
1267 pdb_set_hours(account, logonHours.data,
1268 logonHours.length, PDB_CHANGED);
1272 if (pdb_get_bad_password_count(account) != badPwdCount)
1273 pdb_set_bad_password_count(account, badPwdCount, PDB_CHANGED);
1275 if (pdb_get_logon_count(account) != logonCount)
1276 pdb_set_logon_count(account, logonCount, PDB_CHANGED);
1278 if (!nt_time_is_zero(&pwdLastSet)) {
1279 unix_time = nt_time_to_unix(pwdLastSet);
1280 stored_time = pdb_get_pass_last_set_time(account);
1281 if (stored_time != unix_time)
1282 pdb_set_pass_last_set_time(account, unix_time, PDB_CHANGED);
1283 } else {
1284 /* no last set time, make it now */
1285 pdb_set_pass_last_set_time(account, time(NULL), PDB_CHANGED);
1288 if (!nt_time_is_zero(&accountExpires)) {
1289 unix_time = nt_time_to_unix(accountExpires);
1290 stored_time = pdb_get_kickoff_time(account);
1291 if (stored_time != unix_time)
1292 pdb_set_kickoff_time(account, unix_time, PDB_CHANGED);
1295 /* Decode hashes from password hash
1296 Note that win2000 may send us all zeros for the hashes if it doesn't
1297 think this channel is secure enough - don't set the passwords at all
1298 in that case
1300 if (dBCSPwd.length == 16 && memcmp(dBCSPwd.data, zero_buf, 16) != 0) {
1301 pdb_set_lanman_passwd(account, dBCSPwd.data, PDB_CHANGED);
1304 if (unicodePwd.length == 16 && memcmp(unicodePwd.data, zero_buf, 16) != 0) {
1305 pdb_set_nt_passwd(account, unicodePwd.data, PDB_CHANGED);
1308 /* TODO: history */
1310 /* TODO: account expiry time */
1312 pdb_set_acct_ctrl(account, acct_flags, PDB_CHANGED);
1314 pdb_set_domain(account, lp_workgroup(), PDB_CHANGED);
1316 DEBUG(0,("sam_account_from_object(%s, %s) done\n",
1317 sAMAccountName, sid_string_dbg(&objectSid)));
1318 return NT_STATUS_OK;
1321 /****************************************************************
1322 ****************************************************************/
1324 static NTSTATUS handle_account_object(struct dssync_passdb *pctx,
1325 TALLOC_CTX *mem_ctx,
1326 struct dssync_passdb_obj *obj)
1328 struct drsuapi_DsReplicaObjectListItemEx *cur = obj->cur;
1329 NTSTATUS status;
1330 fstring account;
1331 struct samu *sam_account=NULL;
1332 GROUP_MAP map;
1333 struct group *grp;
1334 struct dom_sid user_sid;
1335 struct dom_sid group_sid;
1336 struct passwd *passwd = NULL;
1337 uint32_t acct_flags;
1338 uint32_t rid;
1340 const char *sAMAccountName;
1341 uint32_t sAMAccountType;
1342 uint32_t userAccountControl;
1344 user_sid = cur->object.identifier->sid;
1345 GET_STRING_EX(sAMAccountName, true);
1346 GET_UINT32_EX(sAMAccountType, true);
1347 GET_UINT32_EX(userAccountControl, true);
1349 status = dom_sid_split_rid(mem_ctx, &user_sid, NULL, &rid);
1350 if (!NT_STATUS_IS_OK(status)) {
1351 return status;
1354 fstrcpy(account, sAMAccountName);
1355 if (rid == DOMAIN_RID_GUEST) {
1357 * pdb_getsampwsid() has special handling for DOMAIN_RID_GUEST
1358 * that's why we need to ignore it here.
1360 * pdb_smbpasswd.c also has some DOMAIN_RID_GUEST related
1361 * code...
1363 DEBUG(0,("Ignore %s - %s\n", account, sid_string_dbg(&user_sid)));
1364 return NT_STATUS_OK;
1366 DEBUG(0,("Creating account: %s\n", account));
1368 if ( !(sam_account = samu_new(mem_ctx)) ) {
1369 return NT_STATUS_NO_MEMORY;
1372 acct_flags = ds_uf2acb(userAccountControl);
1373 status = smb_create_user(sam_account, acct_flags, account, &passwd);
1374 if (!NT_STATUS_IS_OK(status)) {
1375 DEBUG(0,("Could not create posix account info for '%s'- %s\n",
1376 account, nt_errstr(status)));
1377 TALLOC_FREE(sam_account);
1378 return status;
1381 DEBUG(3, ("Attempting to find SID %s for user %s in the passdb\n",
1382 sid_string_dbg(&user_sid), account));
1383 if (!pdb_getsampwsid(sam_account, &user_sid)) {
1384 sam_account_from_object(sam_account, cur);
1385 DEBUG(3, ("Attempting to add user SID %s for user %s in the passdb\n",
1386 sid_string_dbg(&user_sid),
1387 pdb_get_username(sam_account)));
1388 if (!NT_STATUS_IS_OK(pdb_add_sam_account(sam_account))) {
1389 DEBUG(1, ("SAM Account for %s failed to be added to the passdb!\n",
1390 account));
1391 TALLOC_FREE(sam_account);
1392 return NT_STATUS_ACCESS_DENIED;
1394 } else {
1395 sam_account_from_object(sam_account, cur);
1396 DEBUG(3, ("Attempting to update user SID %s for user %s in the passdb\n",
1397 sid_string_dbg(&user_sid),
1398 pdb_get_username(sam_account)));
1399 if (!NT_STATUS_IS_OK(pdb_update_sam_account(sam_account))) {
1400 DEBUG(1, ("SAM Account for %s failed to be updated in the passdb!\n",
1401 account));
1402 TALLOC_FREE(sam_account);
1403 return NT_STATUS_ACCESS_DENIED;
1407 if (pdb_get_group_sid(sam_account) == NULL) {
1408 TALLOC_FREE(sam_account);
1409 return NT_STATUS_UNSUCCESSFUL;
1412 group_sid = *pdb_get_group_sid(sam_account);
1414 if (!pdb_getgrsid(&map, group_sid)) {
1415 DEBUG(0, ("Primary group of %s has no mapping!\n",
1416 pdb_get_username(sam_account)));
1417 } else {
1418 if (map.gid != passwd->pw_gid) {
1419 if (!(grp = getgrgid(map.gid))) {
1420 DEBUG(0, ("Could not find unix group %lu for user %s (group SID=%s)\n",
1421 (unsigned long)map.gid, pdb_get_username(sam_account),
1422 sid_string_dbg(&group_sid)));
1423 } else {
1424 smb_set_primary_group(grp->gr_name, pdb_get_username(sam_account));
1429 if ( !passwd ) {
1430 DEBUG(1, ("No unix user for this account (%s), cannot adjust mappings\n",
1431 pdb_get_username(sam_account)));
1434 TALLOC_FREE(sam_account);
1435 return NT_STATUS_OK;
1438 /****************************************************************
1439 ****************************************************************/
1441 static NTSTATUS handle_alias_object(struct dssync_passdb *pctx,
1442 TALLOC_CTX *mem_ctx,
1443 struct dssync_passdb_obj *obj)
1445 struct drsuapi_DsReplicaObjectListItemEx *cur = obj->cur;
1446 NTSTATUS status;
1447 fstring name;
1448 fstring comment;
1449 struct group *grp = NULL;
1450 struct dom_sid group_sid;
1451 uint32_t rid = 0;
1452 struct dom_sid *dom_sid = NULL;
1453 fstring sid_string;
1454 GROUP_MAP map;
1455 bool insert = true;
1457 const char *sAMAccountName;
1458 uint32_t sAMAccountType;
1459 uint32_t groupType;
1460 const char *description;
1461 uint32_t i;
1462 uint32_t num_members = 0;
1463 struct drsuapi_DsReplicaObjectIdentifier3 *members = NULL;
1465 group_sid = cur->object.identifier->sid;
1466 GET_STRING_EX(sAMAccountName, true);
1467 GET_UINT32_EX(sAMAccountType, true);
1468 GET_UINT32_EX(groupType, true);
1469 GET_STRING(description);
1471 status = find_drsuapi_attr_dn(obj, cur, DRSUAPI_ATTID_member,
1472 &num_members, &members);
1473 if (NT_STATUS_EQUAL(status, NT_STATUS_PROPSET_NOT_FOUND)) {
1474 status = NT_STATUS_OK;
1476 if (!NT_STATUS_IS_OK(status)) {
1477 return status;
1480 fstrcpy(name, sAMAccountName);
1481 fstrcpy(comment, description);
1483 dom_sid_split_rid(mem_ctx, &group_sid, &dom_sid, &rid);
1485 sid_to_fstring(sid_string, &group_sid);
1486 DEBUG(0,("Creating alias[%s] - %s members[%u]\n",
1487 name, sid_string, num_members));
1489 status = dssync_insert_obj(pctx, pctx->aliases, obj);
1490 if (!NT_STATUS_IS_OK(status)) {
1491 return status;
1494 if (pdb_getgrsid(&map, group_sid)) {
1495 if ( map.gid != -1 )
1496 grp = getgrgid(map.gid);
1497 insert = false;
1500 if (grp == NULL) {
1501 gid_t gid;
1503 /* No group found from mapping, find it from its name. */
1504 if ((grp = getgrnam(name)) == NULL) {
1506 /* No appropriate group found, create one */
1508 DEBUG(0,("Creating unix group: '%s'\n", name));
1510 if (smb_create_group(name, &gid) != 0)
1511 return NT_STATUS_ACCESS_DENIED;
1513 if ((grp = getgrgid(gid)) == NULL)
1514 return NT_STATUS_ACCESS_DENIED;
1518 map.gid = grp->gr_gid;
1519 map.sid = group_sid;
1521 if (dom_sid_equal(dom_sid, &global_sid_Builtin)) {
1523 * pdb_ldap does not like SID_NAME_WKN_GRP...
1525 * map.sid_name_use = SID_NAME_WKN_GRP;
1527 map.sid_name_use = SID_NAME_ALIAS;
1528 } else {
1529 map.sid_name_use = SID_NAME_ALIAS;
1532 fstrcpy(map.nt_name, name);
1533 if (description) {
1534 fstrcpy(map.comment, comment);
1535 } else {
1536 fstrcpy(map.comment, "");
1539 if (insert)
1540 pdb_add_group_mapping_entry(&map);
1541 else
1542 pdb_update_group_mapping_entry(&map);
1544 for (i=0; i < num_members; i++) {
1545 struct dssync_passdb_mem *mem;
1547 status = dssync_create_mem(pctx, obj,
1548 true /* active */,
1549 &members[i], &mem);
1550 if (!NT_STATUS_IS_OK(status)) {
1551 return status;
1555 return NT_STATUS_OK;
1558 /****************************************************************
1559 ****************************************************************/
1561 static NTSTATUS handle_group_object(struct dssync_passdb *pctx,
1562 TALLOC_CTX *mem_ctx,
1563 struct dssync_passdb_obj *obj)
1565 struct drsuapi_DsReplicaObjectListItemEx *cur = obj->cur;
1566 NTSTATUS status;
1567 fstring name;
1568 fstring comment;
1569 struct group *grp = NULL;
1570 struct dom_sid group_sid;
1571 fstring sid_string;
1572 GROUP_MAP map;
1573 bool insert = true;
1575 const char *sAMAccountName;
1576 uint32_t sAMAccountType;
1577 uint32_t groupType;
1578 const char *description;
1579 uint32_t i;
1580 uint32_t num_members = 0;
1581 struct drsuapi_DsReplicaObjectIdentifier3 *members = NULL;
1583 group_sid = cur->object.identifier->sid;
1584 GET_STRING_EX(sAMAccountName, true);
1585 GET_UINT32_EX(sAMAccountType, true);
1586 GET_UINT32_EX(groupType, true);
1587 GET_STRING(description);
1589 status = find_drsuapi_attr_dn(obj, cur, DRSUAPI_ATTID_member,
1590 &num_members, &members);
1591 if (NT_STATUS_EQUAL(status, NT_STATUS_PROPSET_NOT_FOUND)) {
1592 status = NT_STATUS_OK;
1594 if (!NT_STATUS_IS_OK(status)) {
1595 return status;
1598 fstrcpy(name, sAMAccountName);
1599 fstrcpy(comment, description);
1601 sid_to_fstring(sid_string, &group_sid);
1602 DEBUG(0,("Creating group[%s] - %s members [%u]\n",
1603 name, sid_string, num_members));
1605 status = dssync_insert_obj(pctx, pctx->groups, obj);
1606 if (!NT_STATUS_IS_OK(status)) {
1607 return status;
1610 if (pdb_getgrsid(&map, group_sid)) {
1611 if ( map.gid != -1 )
1612 grp = getgrgid(map.gid);
1613 insert = false;
1616 if (grp == NULL) {
1617 gid_t gid;
1619 /* No group found from mapping, find it from its name. */
1620 if ((grp = getgrnam(name)) == NULL) {
1622 /* No appropriate group found, create one */
1624 DEBUG(0,("Creating unix group: '%s'\n", name));
1626 if (smb_create_group(name, &gid) != 0)
1627 return NT_STATUS_ACCESS_DENIED;
1629 if ((grp = getgrnam(name)) == NULL)
1630 return NT_STATUS_ACCESS_DENIED;
1634 map.gid = grp->gr_gid;
1635 map.sid = group_sid;
1636 map.sid_name_use = SID_NAME_DOM_GRP;
1637 fstrcpy(map.nt_name, name);
1638 if (description) {
1639 fstrcpy(map.comment, comment);
1640 } else {
1641 fstrcpy(map.comment, "");
1644 if (insert)
1645 pdb_add_group_mapping_entry(&map);
1646 else
1647 pdb_update_group_mapping_entry(&map);
1649 for (i=0; i < num_members; i++) {
1650 struct dssync_passdb_mem *mem;
1652 status = dssync_create_mem(pctx, obj,
1653 true /* active */,
1654 &members[i], &mem);
1655 if (!NT_STATUS_IS_OK(status)) {
1656 return status;
1660 return NT_STATUS_OK;
1663 /****************************************************************
1664 ****************************************************************/
1666 static NTSTATUS handle_interdomain_trust_object(struct dssync_passdb *pctx,
1667 TALLOC_CTX *mem_ctx,
1668 struct dssync_passdb_obj *obj)
1670 struct drsuapi_DsReplicaObjectListItemEx *cur = obj->cur;
1671 DEBUG(0,("trust: %s\n", cur->object.identifier->dn));
1672 return NT_STATUS_NOT_IMPLEMENTED;
1675 /****************************************************************
1676 ****************************************************************/
1678 struct dssync_object_table_t {
1679 uint32_t type;
1680 NTSTATUS (*fn) (struct dssync_passdb *pctx,
1681 TALLOC_CTX *mem_ctx,
1682 struct dssync_passdb_obj *obj);
1685 static const struct dssync_object_table_t dssync_object_table[] = {
1686 { ATYPE_NORMAL_ACCOUNT, handle_account_object },
1687 { ATYPE_WORKSTATION_TRUST, handle_account_object },
1688 { ATYPE_SECURITY_LOCAL_GROUP, handle_alias_object },
1689 { ATYPE_SECURITY_GLOBAL_GROUP, handle_group_object },
1690 { ATYPE_INTERDOMAIN_TRUST, handle_interdomain_trust_object },
1693 /****************************************************************
1694 ****************************************************************/
1696 static NTSTATUS parse_object(struct dssync_passdb *pctx,
1697 TALLOC_CTX *mem_ctx,
1698 struct drsuapi_DsReplicaObjectListItemEx *cur)
1700 NTSTATUS status = NT_STATUS_OK;
1701 DATA_BLOB *blob;
1702 int i = 0;
1703 int a = 0;
1704 struct drsuapi_DsReplicaAttribute *attr;
1706 char *name = NULL;
1707 uint32_t uacc = 0;
1708 uint32_t sam_type = 0;
1710 DEBUG(3, ("parsing object '%s'\n", cur->object.identifier->dn));
1712 for (i=0; i < cur->object.attribute_ctr.num_attributes; i++) {
1714 attr = &cur->object.attribute_ctr.attributes[i];
1716 if (attr->value_ctr.num_values != 1) {
1717 continue;
1720 if (!attr->value_ctr.values[0].blob) {
1721 continue;
1724 blob = attr->value_ctr.values[0].blob;
1726 switch (attr->attid) {
1727 case DRSUAPI_ATTID_sAMAccountName:
1728 pull_string_talloc(mem_ctx, NULL, 0, &name,
1729 blob->data, blob->length,
1730 STR_UNICODE);
1731 break;
1732 case DRSUAPI_ATTID_sAMAccountType:
1733 sam_type = IVAL(blob->data, 0);
1734 break;
1735 case DRSUAPI_ATTID_userAccountControl:
1736 uacc = IVAL(blob->data, 0);
1737 break;
1738 default:
1739 break;
1743 for (a=0; a < ARRAY_SIZE(dssync_object_table); a++) {
1744 if (sam_type == dssync_object_table[a].type) {
1745 if (dssync_object_table[a].fn) {
1746 struct dssync_passdb_obj *obj;
1747 status = dssync_create_obj(pctx, pctx->all,
1748 sam_type, cur, &obj);
1749 if (!NT_STATUS_IS_OK(status)) {
1750 break;
1752 status = dssync_object_table[a].fn(pctx,
1753 mem_ctx,
1754 obj);
1755 break;
1760 return status;
1763 static NTSTATUS parse_link(struct dssync_passdb *pctx,
1764 TALLOC_CTX *mem_ctx,
1765 struct drsuapi_DsReplicaLinkedAttribute *cur)
1767 struct drsuapi_DsReplicaObjectIdentifier3 *id3;
1768 const DATA_BLOB *blob;
1769 enum ndr_err_code ndr_err;
1770 NTSTATUS status;
1771 bool active = false;
1772 struct dssync_passdb_mem *mem;
1773 struct dssync_passdb_obj *obj;
1775 if (cur->attid != DRSUAPI_ATTID_member) {
1776 return NT_STATUS_OK;
1779 if (cur->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE) {
1780 active = true;
1783 DEBUG(3, ("parsing link '%s' - %s\n",
1784 cur->identifier->dn, active?"adding":"deleting"));
1786 blob = cur->value.blob;
1788 if (blob == NULL) {
1789 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1792 obj = dssync_search_obj_by_guid(pctx, pctx->all, &cur->identifier->guid);
1793 if (obj == NULL) {
1794 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1797 id3 = talloc_zero(obj, struct drsuapi_DsReplicaObjectIdentifier3);
1798 if (id3 == NULL) {
1799 return NT_STATUS_NO_MEMORY;
1802 /* windows sometimes sends an extra two pad bytes here */
1803 ndr_err = ndr_pull_struct_blob(blob, id3, id3,
1804 (ndr_pull_flags_fn_t)ndr_pull_drsuapi_DsReplicaObjectIdentifier3);
1805 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1806 status = ndr_map_error2ntstatus(ndr_err);
1807 return status;
1810 status = dssync_create_mem(pctx, obj,
1811 active,
1812 id3, &mem);
1813 if (!NT_STATUS_IS_OK(status)) {
1814 return status;
1817 return NT_STATUS_OK;
1820 /****************************************************************
1821 ****************************************************************/
1823 static NTSTATUS passdb_process_objects(struct dssync_context *ctx,
1824 TALLOC_CTX *mem_ctx,
1825 struct drsuapi_DsReplicaObjectListItemEx *cur,
1826 struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr)
1828 NTSTATUS status = NT_STATUS_OK;
1829 struct dssync_passdb *pctx =
1830 talloc_get_type_abort(ctx->private_data,
1831 struct dssync_passdb);
1833 for (; cur; cur = cur->next_object) {
1834 status = parse_object(pctx, mem_ctx, cur);
1835 if (!NT_STATUS_IS_OK(status)) {
1836 goto out;
1840 out:
1841 return status;
1844 /****************************************************************
1845 ****************************************************************/
1847 static NTSTATUS passdb_process_links(struct dssync_context *ctx,
1848 TALLOC_CTX *mem_ctx,
1849 uint32_t count,
1850 struct drsuapi_DsReplicaLinkedAttribute *links,
1851 struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr)
1853 NTSTATUS status = NT_STATUS_OK;
1854 struct dssync_passdb *pctx =
1855 talloc_get_type_abort(ctx->private_data,
1856 struct dssync_passdb);
1857 uint32_t i;
1859 for (i = 0; i < count; i++) {
1860 status = parse_link(pctx, mem_ctx, &links[i]);
1861 if (!NT_STATUS_IS_OK(status)) {
1862 goto out;
1866 out:
1867 return status;
1870 /****************************************************************
1871 ****************************************************************/
1873 const struct dssync_ops libnet_dssync_passdb_ops = {
1874 .startup = passdb_startup,
1875 .process_objects = passdb_process_objects,
1876 .process_links = passdb_process_links,
1877 .finish = passdb_finish,