s4-libnet: Fix continue_groupinfo_opengroup to check correct state info
[Samba.git] / source3 / libnet / libnet_dssync_passdb.c
blobb56c2d4451bba2cd4368f066933a726ace006ee0
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 "system/passwd.h"
22 #include "libnet/libnet_dssync.h"
23 #include "../libcli/security/security.h"
24 #include "../libds/common/flags.h"
25 #include "../librpc/gen_ndr/ndr_drsuapi.h"
26 #include "util_tdb.h"
27 #include "dbwrap/dbwrap.h"
28 #include "dbwrap/dbwrap_rbt.h"
29 #include "../libds/common/flag_mapping.h"
30 #include "passdb.h"
32 /****************************************************************
33 ****************************************************************/
35 struct dssync_passdb {
36 struct pdb_methods *methods;
37 struct db_context *all;
38 struct db_context *aliases;
39 struct db_context *groups;
42 struct dssync_passdb_obj {
43 struct dssync_passdb_obj *self;
44 uint32_t type;
45 struct drsuapi_DsReplicaObjectListItemEx *cur;
46 TDB_DATA key;
47 TDB_DATA data;
48 struct db_context *members;
51 struct dssync_passdb_mem {
52 struct dssync_passdb_mem *self;
53 bool active;
54 struct drsuapi_DsReplicaObjectIdentifier3 *cur;
55 struct dssync_passdb_obj *obj;
56 TDB_DATA key;
57 TDB_DATA data;
60 static NTSTATUS dssync_insert_obj(struct dssync_passdb *pctx,
61 struct db_context *db,
62 struct dssync_passdb_obj *obj)
64 NTSTATUS status;
65 struct db_record *rec;
66 TDB_DATA value;
68 rec = dbwrap_fetch_locked(db, talloc_tos(), obj->key);
69 if (rec == NULL) {
70 return NT_STATUS_NO_MEMORY;
73 value = dbwrap_record_get_value(rec);
74 if (value.dsize != 0) {
75 abort();
78 status = dbwrap_record_store(rec, obj->data, TDB_INSERT);
79 if (!NT_STATUS_IS_OK(status)) {
80 TALLOC_FREE(rec);
81 return status;
83 TALLOC_FREE(rec);
84 return NT_STATUS_OK;
87 static struct dssync_passdb_obj *dssync_parse_obj(const TDB_DATA data)
89 struct dssync_passdb_obj *obj;
91 if (data.dsize != sizeof(obj)) {
92 return NULL;
96 * we need to copy the pointer to avoid alignment problems
97 * on some systems.
99 memcpy(&obj, data.dptr, sizeof(obj));
101 return talloc_get_type_abort(obj, struct dssync_passdb_obj);
104 static struct dssync_passdb_obj *dssync_search_obj_by_guid(struct dssync_passdb *pctx,
105 struct db_context *db,
106 const struct GUID *guid)
108 struct dssync_passdb_obj *obj;
109 TDB_DATA key;
110 TDB_DATA data;
111 NTSTATUS status;
113 key = make_tdb_data((const uint8_t *)(const void *)guid,
114 sizeof(*guid));
116 status = dbwrap_fetch(db, talloc_tos(), key, &data);
117 if (!NT_STATUS_IS_OK(status)) {
118 return NULL;
121 obj = dssync_parse_obj(data);
122 return obj;
125 static NTSTATUS dssync_create_obj(struct dssync_passdb *pctx,
126 struct db_context *db,
127 uint32_t type,
128 struct drsuapi_DsReplicaObjectListItemEx *cur,
129 struct dssync_passdb_obj **_obj)
131 NTSTATUS status;
132 struct dssync_passdb_obj *obj;
134 obj = talloc_zero(pctx, struct dssync_passdb_obj);
135 if (obj == NULL) {
136 return NT_STATUS_NO_MEMORY;
138 obj->self = obj;
139 obj->cur = cur;
140 obj->type = type;
141 obj->key = make_tdb_data((const uint8_t *)(void *)&cur->object.identifier->guid,
142 sizeof(cur->object.identifier->guid));
143 obj->data = make_tdb_data((const uint8_t *)(void *)&obj->self,
144 sizeof(obj->self));
146 obj->members = db_open_rbt(obj);
147 if (obj->members == NULL) {
148 return NT_STATUS_NO_MEMORY;
151 status = dssync_insert_obj(pctx, db, obj);
152 if (!NT_STATUS_IS_OK(status)) {
153 TALLOC_FREE(obj);
154 return status;
156 *_obj = obj;
157 return NT_STATUS_OK;
160 static NTSTATUS dssync_insert_mem(struct dssync_passdb *pctx,
161 struct dssync_passdb_obj *obj,
162 struct dssync_passdb_mem *mem)
164 NTSTATUS status;
165 struct db_record *rec;
166 TDB_DATA value;
168 rec = dbwrap_fetch_locked(obj->members, talloc_tos(), mem->key);
169 if (rec == NULL) {
170 return NT_STATUS_NO_MEMORY;
173 value = dbwrap_record_get_value(rec);
174 if (value.dsize != 0) {
175 abort();
178 status = dbwrap_record_store(rec, mem->data, TDB_INSERT);
179 if (!NT_STATUS_IS_OK(status)) {
180 TALLOC_FREE(rec);
181 return status;
183 TALLOC_FREE(rec);
184 return NT_STATUS_OK;
187 static NTSTATUS dssync_create_mem(struct dssync_passdb *pctx,
188 struct dssync_passdb_obj *obj,
189 bool active,
190 struct drsuapi_DsReplicaObjectIdentifier3 *cur,
191 struct dssync_passdb_mem **_mem)
193 NTSTATUS status;
194 struct dssync_passdb_mem *mem;
196 mem = talloc_zero(pctx, struct dssync_passdb_mem);
197 if (mem == NULL) {
198 return NT_STATUS_NO_MEMORY;
200 mem->self = mem;
201 mem->cur = cur;
202 mem->active = active;
203 mem->obj = NULL;
204 mem->key = make_tdb_data((const uint8_t *)(void *)&cur->guid,
205 sizeof(cur->guid));
206 mem->data = make_tdb_data((const uint8_t *)(void *)&mem->self,
207 sizeof(mem->self));
209 status = dssync_insert_mem(pctx, obj, mem);
210 if (!NT_STATUS_IS_OK(status)) {
211 TALLOC_FREE(obj);
212 return status;
214 *_mem = mem;
215 return NT_STATUS_OK;
218 static struct dssync_passdb_mem *dssync_parse_mem(const TDB_DATA data)
220 struct dssync_passdb_mem *mem;
222 if (data.dsize != sizeof(mem)) {
223 return NULL;
227 * we need to copy the pointer to avoid alignment problems
228 * on some systems.
230 memcpy(&mem, data.dptr, sizeof(mem));
232 return talloc_get_type_abort(mem, struct dssync_passdb_mem);
235 static NTSTATUS passdb_startup(struct dssync_context *ctx, TALLOC_CTX *mem_ctx,
236 struct replUpToDateVectorBlob **pold_utdv)
238 NTSTATUS status;
239 struct dssync_passdb *pctx;
241 pctx = talloc_zero(mem_ctx, struct dssync_passdb);
242 if (pctx == NULL) {
243 return NT_STATUS_NO_MEMORY;
246 if (ctx->output_filename) {
247 status = make_pdb_method_name(&pctx->methods, ctx->output_filename);
248 } else {
249 status = make_pdb_method_name(&pctx->methods, lp_passdb_backend());
252 if (!NT_STATUS_IS_OK(status)) {
253 return status;
256 pctx->all = db_open_rbt(pctx);
257 if (pctx->all == NULL) {
258 return NT_STATUS_NO_MEMORY;
260 pctx->aliases = db_open_rbt(pctx);
261 if (pctx->aliases == NULL) {
262 return NT_STATUS_NO_MEMORY;
264 pctx->groups = db_open_rbt(pctx);
265 if (pctx->groups == NULL) {
266 return NT_STATUS_NO_MEMORY;
269 ctx->private_data = pctx;
271 return status;
274 /****************************************************************
275 ****************************************************************/
277 struct dssync_passdb_traverse_amembers {
278 struct dssync_context *ctx;
279 struct dssync_passdb_obj *obj;
280 const char *name;
281 uint32_t idx;
284 struct dssync_passdb_traverse_aliases {
285 struct dssync_context *ctx;
286 const char *name;
287 uint32_t idx;
290 static int dssync_passdb_traverse_amembers(struct db_record *rec,
291 void *private_data)
293 struct dssync_passdb_traverse_amembers *state =
294 (struct dssync_passdb_traverse_amembers *)private_data;
295 struct dssync_passdb *pctx =
296 talloc_get_type_abort(state->ctx->private_data,
297 struct dssync_passdb);
298 struct dssync_passdb_mem *mem;
299 NTSTATUS status;
300 struct dom_sid alias_sid;
301 struct dom_sid member_sid;
302 const char *member_dn;
303 size_t num_members;
304 size_t i;
305 struct dom_sid *members;
306 bool is_member = false;
307 const char *action;
308 TDB_DATA value;
310 state->idx++;
312 alias_sid = state->obj->cur->object.identifier->sid;
314 value = dbwrap_record_get_value(rec);
315 mem = dssync_parse_mem(value);
316 if (mem == NULL) {
317 return -1;
320 member_sid = mem->cur->sid;
321 member_dn = mem->cur->dn;
323 mem->obj = dssync_search_obj_by_guid(pctx, pctx->all, &mem->cur->guid);
324 if (mem->obj == NULL) {
325 DEBUG(0,("alias[%s] member[%s] can't resolve member - ignoring\n",
326 sid_string_dbg(&alias_sid),
327 is_null_sid(&member_sid)?
328 sid_string_dbg(&member_sid):
329 member_dn));
330 return 0;
333 switch (mem->obj->type) {
334 case ATYPE_DISTRIBUTION_LOCAL_GROUP:
335 case ATYPE_DISTRIBUTION_GLOBAL_GROUP:
336 DEBUG(0, ("alias[%s] ignore distribution group [%s]\n",
337 sid_string_dbg(&alias_sid),
338 member_dn));
339 return 0;
340 default:
341 break;
344 DEBUG(0,("alias[%s] member[%s]\n",
345 sid_string_dbg(&alias_sid),
346 sid_string_dbg(&member_sid)));
348 status = pdb_enum_aliasmem(&alias_sid, talloc_tos(),
349 &members, &num_members);
350 if (!NT_STATUS_IS_OK(status)) {
351 DEBUG(0, ("Could not find current alias members %s - %s\n",
352 sid_string_dbg(&alias_sid),
353 nt_errstr(status)));
354 return -1;
357 for (i=0; i < num_members; i++) {
358 bool match;
360 match = dom_sid_equal(&members[i], &member_sid);
361 if (match) {
362 is_member = true;
363 break;
367 status = NT_STATUS_OK;
368 action = "none";
369 if (!is_member && mem->active) {
370 action = "add";
371 pdb_add_aliasmem(&alias_sid, &member_sid);
372 } else if (is_member && !mem->active) {
373 action = "delete";
374 pdb_del_aliasmem(&alias_sid, &member_sid);
376 if (!NT_STATUS_IS_OK(status)) {
377 DEBUG(0, ("Could not %s %s as alias members of %s - %s\n",
378 action,
379 sid_string_dbg(&member_sid),
380 sid_string_dbg(&alias_sid),
381 nt_errstr(status)));
382 return -1;
385 return 0;
388 static int dssync_passdb_traverse_aliases(struct db_record *rec,
389 void *private_data)
391 struct dssync_passdb_traverse_aliases *state =
392 (struct dssync_passdb_traverse_aliases *)private_data;
393 struct dssync_passdb *pctx =
394 talloc_get_type_abort(state->ctx->private_data,
395 struct dssync_passdb);
396 struct dssync_passdb_traverse_amembers mstate;
397 struct dssync_passdb_obj *obj;
398 TDB_DATA value;
399 NTSTATUS status;
401 state->idx++;
402 if (pctx->methods == NULL) {
403 return -1;
406 value = dbwrap_record_get_value(rec);
407 obj = dssync_parse_obj(value);
408 if (obj == NULL) {
409 return -1;
412 ZERO_STRUCT(mstate);
413 mstate.ctx = state->ctx;
414 mstate.name = "members";
415 mstate.obj = obj;
416 status = dbwrap_traverse_read(obj->members,
417 dssync_passdb_traverse_amembers,
418 &mstate, NULL);
419 if (!NT_STATUS_IS_OK(status)) {
420 return -1;
423 return 0;
426 struct dssync_passdb_traverse_gmembers {
427 struct dssync_context *ctx;
428 struct dssync_passdb_obj *obj;
429 const char *name;
430 uint32_t idx;
433 struct dssync_passdb_traverse_groups {
434 struct dssync_context *ctx;
435 const char *name;
436 uint32_t idx;
439 static int dssync_passdb_traverse_gmembers(struct db_record *rec,
440 void *private_data)
442 struct dssync_passdb_traverse_gmembers *state =
443 (struct dssync_passdb_traverse_gmembers *)private_data;
444 struct dssync_passdb *pctx =
445 talloc_get_type_abort(state->ctx->private_data,
446 struct dssync_passdb);
447 struct dssync_passdb_mem *mem;
448 NTSTATUS status;
449 char *nt_member = NULL;
450 char **unix_members;
451 struct dom_sid group_sid;
452 struct dom_sid member_sid;
453 struct samu *member = NULL;
454 const char *member_dn = NULL;
455 GROUP_MAP *map;
456 struct group *grp;
457 uint32_t rid;
458 bool is_unix_member = false;
459 TDB_DATA value;
461 state->idx++;
463 group_sid = state->obj->cur->object.identifier->sid;
465 status = dom_sid_split_rid(talloc_tos(), &group_sid, NULL, &rid);
466 if (!NT_STATUS_IS_OK(status)) {
467 return -1;
470 value = dbwrap_record_get_value(rec);
472 mem = dssync_parse_mem(value);
473 if (mem == NULL) {
474 return -1;
477 member_sid = mem->cur->sid;
478 member_dn = mem->cur->dn;
480 mem->obj = dssync_search_obj_by_guid(pctx, pctx->all, &mem->cur->guid);
481 if (mem->obj == NULL) {
482 DEBUG(0,("group[%s] member[%s] can't resolve member - ignoring\n",
483 sid_string_dbg(&group_sid),
484 is_null_sid(&member_sid)?
485 sid_string_dbg(&member_sid):
486 member_dn));
487 return 0;
490 member_sid = mem->obj->cur->object.identifier->sid;
491 member_dn = mem->obj->cur->object.identifier->dn;
493 switch (mem->obj->type) {
494 case ATYPE_SECURITY_LOCAL_GROUP:
495 case ATYPE_SECURITY_GLOBAL_GROUP:
496 DEBUG(0, ("Group[%s] ignore member group [%s]\n",
497 sid_string_dbg(&group_sid),
498 sid_string_dbg(&member_sid)));
499 return 0;
501 case ATYPE_DISTRIBUTION_LOCAL_GROUP:
502 case ATYPE_DISTRIBUTION_GLOBAL_GROUP:
503 DEBUG(0, ("Group[%s] ignore distribution group [%s]\n",
504 sid_string_dbg(&group_sid),
505 member_dn));
506 return 0;
507 default:
508 break;
511 map = talloc_zero(NULL, GROUP_MAP);
512 if (!map) {
513 return -1;
516 if (!get_domain_group_from_sid(group_sid, map)) {
517 DEBUG(0, ("Could not find global group %s\n",
518 sid_string_dbg(&group_sid)));
519 //return NT_STATUS_NO_SUCH_GROUP;
520 TALLOC_FREE(map);
521 return -1;
524 if (!(grp = getgrgid(map->gid))) {
525 DEBUG(0, ("Could not find unix group %lu\n",
526 (unsigned long)map->gid));
527 //return NT_STATUS_NO_SUCH_GROUP;
528 TALLOC_FREE(map);
529 return -1;
532 TALLOC_FREE(map);
534 DEBUG(0,("Group members of %s: ", grp->gr_name));
536 if ( !(member = samu_new(talloc_tos())) ) {
537 //return NT_STATUS_NO_MEMORY;
538 return -1;
541 if (!pdb_getsampwsid(member, &member_sid)) {
542 DEBUG(1, ("Found bogus group member: (member_sid=%s group=%s)\n",
543 sid_string_tos(&member_sid), grp->gr_name));
544 TALLOC_FREE(member);
545 return -1;
548 if (pdb_get_group_rid(member) == rid) {
549 DEBUGADD(0,("%s(primary),", pdb_get_username(member)));
550 TALLOC_FREE(member);
551 return -1;
554 DEBUGADD(0,("%s,", pdb_get_username(member)));
555 nt_member = talloc_strdup(talloc_tos(), pdb_get_username(member));
556 TALLOC_FREE(member);
558 DEBUGADD(0,("\n"));
560 unix_members = grp->gr_mem;
562 while (*unix_members) {
563 if (strcmp(*unix_members, nt_member) == 0) {
564 is_unix_member = true;
565 break;
567 unix_members += 1;
570 if (!is_unix_member && mem->active) {
571 smb_add_user_group(grp->gr_name, nt_member);
572 } else if (is_unix_member && !mem->active) {
573 smb_delete_user_group(grp->gr_name, nt_member);
576 return 0;
579 static int dssync_passdb_traverse_groups(struct db_record *rec,
580 void *private_data)
582 struct dssync_passdb_traverse_groups *state =
583 (struct dssync_passdb_traverse_groups *)private_data;
584 struct dssync_passdb *pctx =
585 talloc_get_type_abort(state->ctx->private_data,
586 struct dssync_passdb);
587 struct dssync_passdb_traverse_gmembers mstate;
588 struct dssync_passdb_obj *obj;
589 TDB_DATA value;
590 NTSTATUS status;
592 state->idx++;
593 if (pctx->methods == NULL) {
594 return -1;
597 value = dbwrap_record_get_value(rec);
599 obj = dssync_parse_obj(value);
600 if (obj == NULL) {
601 return -1;
604 ZERO_STRUCT(mstate);
605 mstate.ctx = state->ctx;
606 mstate.name = "members";
607 mstate.obj = obj;
608 status = dbwrap_traverse_read(obj->members,
609 dssync_passdb_traverse_gmembers,
610 &mstate, NULL);
611 if (!NT_STATUS_IS_OK(status)) {
612 return -1;
615 return 0;
618 static NTSTATUS passdb_finish(struct dssync_context *ctx, TALLOC_CTX *mem_ctx,
619 struct replUpToDateVectorBlob *new_utdv)
621 struct dssync_passdb *pctx =
622 talloc_get_type_abort(ctx->private_data,
623 struct dssync_passdb);
624 struct dssync_passdb_traverse_aliases astate;
625 struct dssync_passdb_traverse_groups gstate;
626 NTSTATUS status;
628 ZERO_STRUCT(astate);
629 astate.ctx = ctx;
630 astate.name = "aliases";
631 status = dbwrap_traverse_read(pctx->aliases,
632 dssync_passdb_traverse_aliases,
633 &astate, NULL);
634 if (!NT_STATUS_IS_OK(status)) {
635 return NT_STATUS_INTERNAL_ERROR;
638 ZERO_STRUCT(gstate);
639 gstate.ctx = ctx;
640 gstate.name = "groups";
641 status = dbwrap_traverse_read(pctx->groups,
642 dssync_passdb_traverse_groups,
643 &gstate, NULL);
644 if (!NT_STATUS_IS_OK(status)) {
645 return NT_STATUS_INTERNAL_ERROR;
648 TALLOC_FREE(pctx->methods);
649 TALLOC_FREE(pctx);
651 return NT_STATUS_OK;
654 /****************************************************************
655 ****************************************************************/
657 static NTSTATUS smb_create_user(TALLOC_CTX *mem_ctx,
658 uint32_t acct_flags,
659 const char *account,
660 struct passwd **passwd_p)
662 struct passwd *passwd;
663 char *add_script = NULL;
665 passwd = Get_Pwnam_alloc(mem_ctx, account);
666 if (passwd) {
667 *passwd_p = passwd;
668 return NT_STATUS_OK;
671 /* Create appropriate user */
672 if (acct_flags & ACB_NORMAL) {
673 add_script = talloc_strdup(mem_ctx, lp_adduser_script());
674 } else if ( (acct_flags & ACB_WSTRUST) ||
675 (acct_flags & ACB_SVRTRUST) ||
676 (acct_flags & ACB_DOMTRUST) ) {
677 add_script = talloc_strdup(mem_ctx, lp_addmachine_script());
678 } else {
679 DEBUG(1, ("Unknown user type: %s\n",
680 pdb_encode_acct_ctrl(acct_flags, NEW_PW_FORMAT_SPACE_PADDED_LEN)));
681 return NT_STATUS_UNSUCCESSFUL;
684 if (!add_script) {
685 return NT_STATUS_NO_MEMORY;
688 if (*add_script) {
689 int add_ret;
690 add_script = talloc_all_string_sub(mem_ctx, add_script,
691 "%u", account);
692 if (!add_script) {
693 return NT_STATUS_NO_MEMORY;
695 add_ret = smbrun(add_script, NULL);
696 DEBUG(add_ret ? 0 : 1,("fetch_account: Running the command `%s' "
697 "gave %d\n", add_script, add_ret));
698 if (add_ret == 0) {
699 smb_nscd_flush_user_cache();
703 /* try and find the possible unix account again */
704 passwd = Get_Pwnam_alloc(mem_ctx, account);
705 if (!passwd) {
706 return NT_STATUS_NO_SUCH_USER;
709 *passwd_p = passwd;
711 return NT_STATUS_OK;
714 static struct drsuapi_DsReplicaAttribute *find_drsuapi_attr(
715 const struct drsuapi_DsReplicaObjectListItemEx *cur,
716 uint32_t attid)
718 int i = 0;
720 for (i = 0; i < cur->object.attribute_ctr.num_attributes; i++) {
721 struct drsuapi_DsReplicaAttribute *attr;
723 attr = &cur->object.attribute_ctr.attributes[i];
725 if (attr->attid == attid) {
726 return attr;
730 return NULL;
733 static NTSTATUS find_drsuapi_attr_string(TALLOC_CTX *mem_ctx,
734 const struct drsuapi_DsReplicaObjectListItemEx *cur,
735 uint32_t attid,
736 uint32_t *_count,
737 char ***_array)
739 struct drsuapi_DsReplicaAttribute *attr;
740 char **array;
741 uint32_t a;
743 attr = find_drsuapi_attr(cur, attid);
744 if (attr == NULL) {
745 return NT_STATUS_PROPSET_NOT_FOUND;
748 array = talloc_array(mem_ctx, char *, attr->value_ctr.num_values);
749 if (array == NULL) {
750 return NT_STATUS_NO_MEMORY;
753 for (a = 0; a < attr->value_ctr.num_values; a++) {
754 const DATA_BLOB *blob;
755 ssize_t ret;
757 blob = attr->value_ctr.values[a].blob;
759 if (blob == NULL) {
760 return NT_STATUS_INTERNAL_DB_CORRUPTION;
763 ret = pull_string_talloc(array, NULL, 0, &array[a],
764 blob->data, blob->length,
765 STR_UNICODE);
766 if (ret == -1) {
767 //TODO
768 return NT_STATUS_INTERNAL_ERROR;
772 *_count = attr->value_ctr.num_values;
773 *_array = array;
774 return NT_STATUS_OK;
777 static NTSTATUS find_drsuapi_attr_int32(TALLOC_CTX *mem_ctx,
778 const struct drsuapi_DsReplicaObjectListItemEx *cur,
779 uint32_t attid,
780 uint32_t *_count,
781 int32_t **_array)
783 struct drsuapi_DsReplicaAttribute *attr;
784 int32_t *array;
785 uint32_t a;
787 attr = find_drsuapi_attr(cur, attid);
788 if (attr == NULL) {
789 return NT_STATUS_PROPSET_NOT_FOUND;
792 array = talloc_array(mem_ctx, int32_t, attr->value_ctr.num_values);
793 if (array == NULL) {
794 return NT_STATUS_NO_MEMORY;
797 for (a = 0; a < attr->value_ctr.num_values; a++) {
798 const DATA_BLOB *blob;
800 blob = attr->value_ctr.values[a].blob;
802 if (blob == NULL) {
803 return NT_STATUS_INTERNAL_DB_CORRUPTION;
806 if (blob->length != 4) {
807 return NT_STATUS_INTERNAL_DB_CORRUPTION;
810 array[a] = IVAL(blob->data, 0);
813 *_count = attr->value_ctr.num_values;
814 *_array = array;
815 return NT_STATUS_OK;
818 static NTSTATUS find_drsuapi_attr_blob(TALLOC_CTX *mem_ctx,
819 const struct drsuapi_DsReplicaObjectListItemEx *cur,
820 uint32_t attid,
821 uint32_t *_count,
822 DATA_BLOB **_array)
824 struct drsuapi_DsReplicaAttribute *attr;
825 DATA_BLOB *array;
826 uint32_t a;
828 attr = find_drsuapi_attr(cur, attid);
829 if (attr == NULL) {
830 return NT_STATUS_PROPSET_NOT_FOUND;
833 array = talloc_array(mem_ctx, DATA_BLOB, attr->value_ctr.num_values);
834 if (array == NULL) {
835 return NT_STATUS_NO_MEMORY;
838 for (a = 0; a < attr->value_ctr.num_values; a++) {
839 const DATA_BLOB *blob;
841 blob = attr->value_ctr.values[a].blob;
843 if (blob == NULL) {
844 return NT_STATUS_INTERNAL_DB_CORRUPTION;
847 array[a] = data_blob_talloc(array, blob->data, blob->length);
848 if (array[a].length != blob->length) {
849 return NT_STATUS_NO_MEMORY;
852 *_count = attr->value_ctr.num_values;
853 *_array = array;
854 return NT_STATUS_OK;
857 static NTSTATUS find_drsuapi_attr_int64(TALLOC_CTX *mem_ctx,
858 const struct drsuapi_DsReplicaObjectListItemEx *cur,
859 uint32_t attid,
860 uint32_t *_count,
861 int64_t **_array)
863 struct drsuapi_DsReplicaAttribute *attr;
864 int64_t *array;
865 uint32_t a;
867 attr = find_drsuapi_attr(cur, attid);
868 if (attr == NULL) {
869 return NT_STATUS_PROPSET_NOT_FOUND;
872 array = talloc_array(mem_ctx, int64_t, attr->value_ctr.num_values);
873 if (array == NULL) {
874 return NT_STATUS_NO_MEMORY;
877 for (a = 0; a < attr->value_ctr.num_values; a++) {
878 const DATA_BLOB *blob;
880 blob = attr->value_ctr.values[a].blob;
882 if (blob == NULL) {
883 return NT_STATUS_INTERNAL_DB_CORRUPTION;
886 if (blob->length != 8) {
887 return NT_STATUS_INTERNAL_DB_CORRUPTION;
890 array[a] = BVAL(blob->data, 0);
892 *_count = attr->value_ctr.num_values;
893 *_array = array;
894 return NT_STATUS_OK;
897 static NTSTATUS find_drsuapi_attr_dn(TALLOC_CTX *mem_ctx,
898 const struct drsuapi_DsReplicaObjectListItemEx *cur,
899 uint32_t attid,
900 uint32_t *_count,
901 struct drsuapi_DsReplicaObjectIdentifier3 **_array)
903 struct drsuapi_DsReplicaAttribute *attr;
904 struct drsuapi_DsReplicaObjectIdentifier3 *array;
905 uint32_t a;
907 attr = find_drsuapi_attr(cur, attid);
908 if (attr == NULL) {
909 return NT_STATUS_PROPSET_NOT_FOUND;
912 array = talloc_array(mem_ctx,
913 struct drsuapi_DsReplicaObjectIdentifier3,
914 attr->value_ctr.num_values);
915 if (array == NULL) {
916 return NT_STATUS_NO_MEMORY;
919 for (a = 0; a < attr->value_ctr.num_values; a++) {
920 const DATA_BLOB *blob;
921 enum ndr_err_code ndr_err;
922 NTSTATUS status;
924 blob = attr->value_ctr.values[a].blob;
926 if (blob == NULL) {
927 return NT_STATUS_INTERNAL_DB_CORRUPTION;
930 /* windows sometimes sends an extra two pad bytes here */
931 ndr_err = ndr_pull_struct_blob(blob, array, &array[a],
932 (ndr_pull_flags_fn_t)ndr_pull_drsuapi_DsReplicaObjectIdentifier3);
933 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
934 status = ndr_map_error2ntstatus(ndr_err);
935 return status;
938 *_count = attr->value_ctr.num_values;
939 *_array = array;
940 return NT_STATUS_OK;
943 #define GET_BLOB_EX(attr, needed) do { \
944 NTSTATUS _status; \
945 uint32_t _cnt; \
946 DATA_BLOB *_vals = NULL; \
947 attr = data_blob_null; \
948 _status = find_drsuapi_attr_blob(mem_ctx, cur, \
949 DRSUAPI_ATTID_ ## attr, \
950 &_cnt, &_vals); \
951 if (NT_STATUS_EQUAL(_status, NT_STATUS_PROPSET_NOT_FOUND)) { \
952 if (!needed) { \
953 _status = NT_STATUS_OK; \
954 _cnt = 0; \
957 if (!NT_STATUS_IS_OK(_status)) { \
958 DEBUG(0,(__location__ "attr[%s] %s\n", \
959 #attr, nt_errstr(_status))); \
960 return _status; \
962 if (_cnt == 0) { \
963 if (needed) { \
964 talloc_free(_vals); \
965 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
966 return NT_STATUS_OBJECT_NAME_NOT_FOUND; \
968 } else if (_cnt > 1) { \
969 talloc_free(_vals); \
970 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
971 return NT_STATUS_INTERNAL_DB_CORRUPTION; \
972 } else { \
973 attr = _vals[0]; \
974 (void)talloc_steal(mem_ctx, _vals[0].data); \
976 talloc_free(_vals); \
977 } while(0)
979 #define GET_STRING_EX(attr, needed) do { \
980 NTSTATUS _status; \
981 uint32_t _cnt; \
982 char **_vals = NULL; \
983 attr = NULL; \
984 _status = find_drsuapi_attr_string(mem_ctx, cur, \
985 DRSUAPI_ATTID_ ## attr, \
986 &_cnt, &_vals); \
987 if (NT_STATUS_EQUAL(_status, NT_STATUS_PROPSET_NOT_FOUND)) { \
988 if (!needed) { \
989 _status = NT_STATUS_OK; \
990 _cnt = 0; \
993 if (!NT_STATUS_IS_OK(_status)) { \
994 DEBUG(0,(__location__ "attr[%s] %s\n", \
995 #attr, nt_errstr(_status))); \
996 return _status; \
998 if (_cnt == 0) { \
999 if (needed) { \
1000 talloc_free(_vals); \
1001 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1002 return NT_STATUS_OBJECT_NAME_NOT_FOUND; \
1004 } else if (_cnt > 1) { \
1005 talloc_free(_vals); \
1006 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1007 return NT_STATUS_INTERNAL_DB_CORRUPTION; \
1008 } else { \
1009 attr = talloc_move(mem_ctx, &_vals[0]); \
1011 talloc_free(_vals); \
1012 } while(0)
1014 #define GET_UINT32_EX(attr, needed) do { \
1015 NTSTATUS _status; \
1016 uint32_t _cnt; \
1017 int32_t*_vals = NULL; \
1018 attr = 0; \
1019 _status = find_drsuapi_attr_int32(mem_ctx, cur, \
1020 DRSUAPI_ATTID_ ## attr, \
1021 &_cnt, &_vals); \
1022 if (NT_STATUS_EQUAL(_status, NT_STATUS_PROPSET_NOT_FOUND)) { \
1023 if (!needed) { \
1024 _status = NT_STATUS_OK; \
1025 _cnt = 0; \
1028 if (!NT_STATUS_IS_OK(_status)) { \
1029 DEBUG(0,(__location__ "attr[%s] %s\n", \
1030 #attr, nt_errstr(_status))); \
1031 return _status; \
1033 if (_cnt == 0) { \
1034 if (needed) { \
1035 talloc_free(_vals); \
1036 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1037 return NT_STATUS_OBJECT_NAME_NOT_FOUND; \
1039 } else if (_cnt > 1) { \
1040 talloc_free(_vals); \
1041 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1042 return NT_STATUS_INTERNAL_DB_CORRUPTION; \
1043 } else { \
1044 attr = (uint32_t)_vals[0]; \
1046 talloc_free(_vals); \
1047 } while(0)
1049 #define GET_UINT64_EX(attr, needed) do { \
1050 NTSTATUS _status; \
1051 uint32_t _cnt; \
1052 int64_t *_vals = NULL; \
1053 attr = 0; \
1054 _status = find_drsuapi_attr_int64(mem_ctx, cur, \
1055 DRSUAPI_ATTID_ ## attr, \
1056 &_cnt, &_vals); \
1057 if (NT_STATUS_EQUAL(_status, NT_STATUS_PROPSET_NOT_FOUND)) { \
1058 if (!needed) { \
1059 _status = NT_STATUS_OK; \
1060 _cnt = 0; \
1063 if (!NT_STATUS_IS_OK(_status)) { \
1064 DEBUG(0,(__location__ "attr[%s] %s\n", \
1065 #attr, nt_errstr(_status))); \
1066 return _status; \
1068 if (_cnt == 0) { \
1069 if (needed) { \
1070 talloc_free(_vals); \
1071 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1072 return NT_STATUS_OBJECT_NAME_NOT_FOUND; \
1074 } else if (_cnt > 1) { \
1075 talloc_free(_vals); \
1076 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1077 return NT_STATUS_INTERNAL_DB_CORRUPTION; \
1078 } else { \
1079 attr = (uint64_t)_vals[0]; \
1081 talloc_free(_vals); \
1082 } while(0)
1084 #define GET_BLOB(attr) GET_BLOB_EX(attr, false)
1085 #define GET_STRING(attr) GET_STRING_EX(attr, false)
1086 #define GET_UINT32(attr) GET_UINT32_EX(attr, false)
1087 #define GET_UINT64(attr) GET_UINT64_EX(attr, false)
1089 /* Convert a struct samu_DELTA to a struct samu. */
1090 #define STRING_CHANGED (old_string && !new_string) ||\
1091 (!old_string && new_string) ||\
1092 (old_string && new_string && (strcmp(old_string, new_string) != 0))
1094 #define STRING_CHANGED_NC(s1,s2) ((s1) && !(s2)) ||\
1095 (!(s1) && (s2)) ||\
1096 ((s1) && (s2) && (strcmp((s1), (s2)) != 0))
1098 /****************************************************************
1099 ****************************************************************/
1101 static NTSTATUS sam_account_from_object(struct samu *account,
1102 struct drsuapi_DsReplicaObjectListItemEx *cur)
1104 TALLOC_CTX *mem_ctx = account;
1105 const char *old_string, *new_string;
1106 time_t unix_time, stored_time;
1107 uchar zero_buf[16];
1108 NTSTATUS status;
1110 NTTIME lastLogon;
1111 NTTIME lastLogoff;
1112 NTTIME pwdLastSet;
1113 NTTIME accountExpires;
1114 const char *sAMAccountName;
1115 const char *displayName;
1116 const char *homeDirectory;
1117 const char *homeDrive;
1118 const char *scriptPath;
1119 const char *profilePath;
1120 const char *description;
1121 const char *userWorkstations;
1122 const char *comment;
1123 DATA_BLOB userParameters;
1124 struct dom_sid objectSid;
1125 uint32_t primaryGroupID;
1126 uint32_t userAccountControl;
1127 DATA_BLOB logonHours;
1128 uint32_t badPwdCount;
1129 uint32_t logonCount;
1130 DATA_BLOB unicodePwd;
1131 DATA_BLOB dBCSPwd;
1133 uint32_t rid = 0;
1134 uint32_t acct_flags;
1135 uint32_t units_per_week;
1137 memset(zero_buf, '\0', sizeof(zero_buf));
1139 objectSid = cur->object.identifier->sid;
1140 GET_STRING_EX(sAMAccountName, true);
1141 DEBUG(0,("sam_account_from_object(%s, %s) start\n",
1142 sAMAccountName, sid_string_dbg(&objectSid)));
1143 GET_UINT64(lastLogon);
1144 GET_UINT64(lastLogoff);
1145 GET_UINT64(pwdLastSet);
1146 GET_UINT64(accountExpires);
1147 GET_STRING(displayName);
1148 GET_STRING(homeDirectory);
1149 GET_STRING(homeDrive);
1150 GET_STRING(scriptPath);
1151 GET_STRING(profilePath);
1152 GET_STRING(description);
1153 GET_STRING(userWorkstations);
1154 GET_STRING(comment);
1155 GET_BLOB(userParameters);
1156 GET_UINT32(primaryGroupID);
1157 GET_UINT32(userAccountControl);
1158 GET_BLOB(logonHours);
1159 GET_UINT32(badPwdCount);
1160 GET_UINT32(logonCount);
1161 GET_BLOB(unicodePwd);
1162 GET_BLOB(dBCSPwd);
1164 status = dom_sid_split_rid(mem_ctx, &objectSid, NULL, &rid);
1165 if (!NT_STATUS_IS_OK(status)) {
1166 return status;
1168 acct_flags = ds_uf2acb(userAccountControl);
1170 /* Username, fullname, home dir, dir drive, logon script, acct
1171 desc, workstations, profile. */
1173 if (sAMAccountName) {
1174 old_string = pdb_get_nt_username(account);
1175 new_string = sAMAccountName;
1177 if (STRING_CHANGED) {
1178 pdb_set_nt_username(account, new_string, PDB_CHANGED);
1181 /* Unix username is the same - for sanity */
1182 old_string = pdb_get_username( account );
1183 if (STRING_CHANGED) {
1184 pdb_set_username(account, new_string, PDB_CHANGED);
1188 if (displayName) {
1189 old_string = pdb_get_fullname(account);
1190 new_string = displayName;
1192 if (STRING_CHANGED)
1193 pdb_set_fullname(account, new_string, PDB_CHANGED);
1196 if (homeDirectory) {
1197 old_string = pdb_get_homedir(account);
1198 new_string = homeDirectory;
1200 if (STRING_CHANGED)
1201 pdb_set_homedir(account, new_string, PDB_CHANGED);
1204 if (homeDrive) {
1205 old_string = pdb_get_dir_drive(account);
1206 new_string = homeDrive;
1208 if (STRING_CHANGED)
1209 pdb_set_dir_drive(account, new_string, PDB_CHANGED);
1212 if (scriptPath) {
1213 old_string = pdb_get_logon_script(account);
1214 new_string = scriptPath;
1216 if (STRING_CHANGED)
1217 pdb_set_logon_script(account, new_string, PDB_CHANGED);
1220 if (description) {
1221 old_string = pdb_get_acct_desc(account);
1222 new_string = description;
1224 if (STRING_CHANGED)
1225 pdb_set_acct_desc(account, new_string, PDB_CHANGED);
1228 if (userWorkstations) {
1229 old_string = pdb_get_workstations(account);
1230 new_string = userWorkstations;
1232 if (STRING_CHANGED)
1233 pdb_set_workstations(account, new_string, PDB_CHANGED);
1236 if (profilePath) {
1237 old_string = pdb_get_profile_path(account);
1238 new_string = profilePath;
1240 if (STRING_CHANGED)
1241 pdb_set_profile_path(account, new_string, PDB_CHANGED);
1244 if (userParameters.data) {
1245 char *newstr;
1246 old_string = pdb_get_munged_dial(account);
1247 newstr = (userParameters.length == 0) ? NULL :
1248 base64_encode_data_blob(talloc_tos(), userParameters);
1250 if (STRING_CHANGED_NC(old_string, newstr))
1251 pdb_set_munged_dial(account, newstr, PDB_CHANGED);
1252 TALLOC_FREE(newstr);
1255 /* User and group sid */
1256 if (rid != 0 && pdb_get_user_rid(account) != rid) {
1257 pdb_set_user_sid_from_rid(account, rid, PDB_CHANGED);
1259 if (primaryGroupID != 0 && pdb_get_group_rid(account) != primaryGroupID) {
1260 pdb_set_group_sid_from_rid(account, primaryGroupID, PDB_CHANGED);
1263 /* Logon and password information */
1264 if (!nt_time_is_zero(&lastLogon)) {
1265 unix_time = nt_time_to_unix(lastLogon);
1266 stored_time = pdb_get_logon_time(account);
1267 if (stored_time != unix_time)
1268 pdb_set_logon_time(account, unix_time, PDB_CHANGED);
1271 if (!nt_time_is_zero(&lastLogoff)) {
1272 unix_time = nt_time_to_unix(lastLogoff);
1273 stored_time = pdb_get_logoff_time(account);
1274 if (stored_time != unix_time)
1275 pdb_set_logoff_time(account, unix_time,PDB_CHANGED);
1278 /* Logon Divs */
1279 units_per_week = logonHours.length * 8;
1281 if (pdb_get_logon_divs(account) != units_per_week) {
1282 pdb_set_logon_divs(account, units_per_week, PDB_CHANGED);
1285 /* Logon Hours Len */
1286 if (units_per_week/8 != pdb_get_hours_len(account)) {
1287 pdb_set_hours_len(account, units_per_week/8, PDB_CHANGED);
1290 /* Logon Hours */
1291 if (logonHours.data) {
1292 char oldstr[44], newstr[44];
1293 pdb_sethexhours(oldstr, pdb_get_hours(account));
1294 pdb_sethexhours(newstr, logonHours.data);
1295 if (!strequal(oldstr, newstr)) {
1296 pdb_set_hours(account, logonHours.data,
1297 logonHours.length, PDB_CHANGED);
1301 if (pdb_get_bad_password_count(account) != badPwdCount)
1302 pdb_set_bad_password_count(account, badPwdCount, PDB_CHANGED);
1304 if (pdb_get_logon_count(account) != logonCount)
1305 pdb_set_logon_count(account, logonCount, PDB_CHANGED);
1307 if (!nt_time_is_zero(&pwdLastSet)) {
1308 unix_time = nt_time_to_unix(pwdLastSet);
1309 stored_time = pdb_get_pass_last_set_time(account);
1310 if (stored_time != unix_time)
1311 pdb_set_pass_last_set_time(account, unix_time, PDB_CHANGED);
1312 } else {
1313 /* no last set time, make it now */
1314 pdb_set_pass_last_set_time(account, time(NULL), PDB_CHANGED);
1317 if (!nt_time_is_zero(&accountExpires)) {
1318 unix_time = nt_time_to_unix(accountExpires);
1319 stored_time = pdb_get_kickoff_time(account);
1320 if (stored_time != unix_time)
1321 pdb_set_kickoff_time(account, unix_time, PDB_CHANGED);
1324 /* Decode hashes from password hash
1325 Note that win2000 may send us all zeros for the hashes if it doesn't
1326 think this channel is secure enough - don't set the passwords at all
1327 in that case
1329 if (dBCSPwd.length == 16 && memcmp(dBCSPwd.data, zero_buf, 16) != 0) {
1330 pdb_set_lanman_passwd(account, dBCSPwd.data, PDB_CHANGED);
1333 if (unicodePwd.length == 16 && memcmp(unicodePwd.data, zero_buf, 16) != 0) {
1334 pdb_set_nt_passwd(account, unicodePwd.data, PDB_CHANGED);
1337 /* TODO: history */
1339 /* TODO: account expiry time */
1341 pdb_set_acct_ctrl(account, acct_flags, PDB_CHANGED);
1343 pdb_set_domain(account, lp_workgroup(), PDB_CHANGED);
1345 DEBUG(0,("sam_account_from_object(%s, %s) done\n",
1346 sAMAccountName, sid_string_dbg(&objectSid)));
1347 return NT_STATUS_OK;
1350 /****************************************************************
1351 ****************************************************************/
1353 static NTSTATUS handle_account_object(struct dssync_passdb *pctx,
1354 TALLOC_CTX *mem_ctx,
1355 struct dssync_passdb_obj *obj)
1357 struct drsuapi_DsReplicaObjectListItemEx *cur = obj->cur;
1358 NTSTATUS status;
1359 fstring account;
1360 struct samu *sam_account=NULL;
1361 GROUP_MAP *map;
1362 struct group *grp;
1363 struct dom_sid user_sid;
1364 struct dom_sid group_sid;
1365 struct passwd *passwd = NULL;
1366 uint32_t acct_flags;
1367 uint32_t rid;
1369 const char *sAMAccountName;
1370 uint32_t sAMAccountType;
1371 uint32_t userAccountControl;
1373 user_sid = cur->object.identifier->sid;
1374 GET_STRING_EX(sAMAccountName, true);
1375 GET_UINT32_EX(sAMAccountType, true);
1376 GET_UINT32_EX(userAccountControl, true);
1378 status = dom_sid_split_rid(mem_ctx, &user_sid, NULL, &rid);
1379 if (!NT_STATUS_IS_OK(status)) {
1380 return status;
1383 fstrcpy(account, sAMAccountName);
1384 if (rid == DOMAIN_RID_GUEST) {
1386 * pdb_getsampwsid() has special handling for DOMAIN_RID_GUEST
1387 * that's why we need to ignore it here.
1389 * pdb_smbpasswd.c also has some DOMAIN_RID_GUEST related
1390 * code...
1392 DEBUG(0,("Ignore %s - %s\n", account, sid_string_dbg(&user_sid)));
1393 return NT_STATUS_OK;
1395 DEBUG(0,("Creating account: %s\n", account));
1397 if ( !(sam_account = samu_new(mem_ctx)) ) {
1398 return NT_STATUS_NO_MEMORY;
1401 acct_flags = ds_uf2acb(userAccountControl);
1402 status = smb_create_user(sam_account, acct_flags, account, &passwd);
1403 if (!NT_STATUS_IS_OK(status)) {
1404 DEBUG(0,("Could not create posix account info for '%s'- %s\n",
1405 account, nt_errstr(status)));
1406 TALLOC_FREE(sam_account);
1407 return status;
1410 DEBUG(3, ("Attempting to find SID %s for user %s in the passdb\n",
1411 sid_string_dbg(&user_sid), account));
1412 if (!pdb_getsampwsid(sam_account, &user_sid)) {
1413 sam_account_from_object(sam_account, cur);
1414 DEBUG(3, ("Attempting to add user SID %s for user %s in the passdb\n",
1415 sid_string_dbg(&user_sid),
1416 pdb_get_username(sam_account)));
1417 if (!NT_STATUS_IS_OK(pdb_add_sam_account(sam_account))) {
1418 DEBUG(1, ("SAM Account for %s failed to be added to the passdb!\n",
1419 account));
1420 TALLOC_FREE(sam_account);
1421 return NT_STATUS_ACCESS_DENIED;
1423 } else {
1424 sam_account_from_object(sam_account, cur);
1425 DEBUG(3, ("Attempting to update user SID %s for user %s in the passdb\n",
1426 sid_string_dbg(&user_sid),
1427 pdb_get_username(sam_account)));
1428 if (!NT_STATUS_IS_OK(pdb_update_sam_account(sam_account))) {
1429 DEBUG(1, ("SAM Account for %s failed to be updated in the passdb!\n",
1430 account));
1431 TALLOC_FREE(sam_account);
1432 return NT_STATUS_ACCESS_DENIED;
1436 if (pdb_get_group_sid(sam_account) == NULL) {
1437 TALLOC_FREE(sam_account);
1438 return NT_STATUS_UNSUCCESSFUL;
1441 group_sid = *pdb_get_group_sid(sam_account);
1443 map = talloc_zero(NULL, GROUP_MAP);
1444 if (!map) {
1445 return NT_STATUS_NO_MEMORY;
1448 if (!pdb_getgrsid(map, group_sid)) {
1449 DEBUG(0, ("Primary group of %s has no mapping!\n",
1450 pdb_get_username(sam_account)));
1451 } else {
1452 if (map->gid != passwd->pw_gid) {
1453 if (!(grp = getgrgid(map->gid))) {
1454 DEBUG(0, ("Could not find unix group %lu for user %s (group SID=%s)\n",
1455 (unsigned long)map->gid, pdb_get_username(sam_account),
1456 sid_string_dbg(&group_sid)));
1457 } else {
1458 smb_set_primary_group(grp->gr_name, pdb_get_username(sam_account));
1463 TALLOC_FREE(map);
1465 if ( !passwd ) {
1466 DEBUG(1, ("No unix user for this account (%s), cannot adjust mappings\n",
1467 pdb_get_username(sam_account)));
1470 TALLOC_FREE(sam_account);
1471 return NT_STATUS_OK;
1474 /****************************************************************
1475 ****************************************************************/
1477 static NTSTATUS handle_alias_object(struct dssync_passdb *pctx,
1478 TALLOC_CTX *mem_ctx,
1479 struct dssync_passdb_obj *obj)
1481 struct drsuapi_DsReplicaObjectListItemEx *cur = obj->cur;
1482 NTSTATUS status;
1483 struct group *grp = NULL;
1484 struct dom_sid group_sid;
1485 uint32_t rid = 0;
1486 struct dom_sid *dom_sid = NULL;
1487 fstring sid_string;
1488 GROUP_MAP *map;
1489 bool insert = true;
1491 const char *sAMAccountName;
1492 uint32_t sAMAccountType;
1493 uint32_t groupType;
1494 const char *description;
1495 uint32_t i;
1496 uint32_t num_members = 0;
1497 struct drsuapi_DsReplicaObjectIdentifier3 *members = NULL;
1499 group_sid = cur->object.identifier->sid;
1500 GET_STRING_EX(sAMAccountName, true);
1501 GET_UINT32_EX(sAMAccountType, true);
1502 GET_UINT32_EX(groupType, true);
1503 GET_STRING(description);
1505 status = find_drsuapi_attr_dn(obj, cur, DRSUAPI_ATTID_member,
1506 &num_members, &members);
1507 if (NT_STATUS_EQUAL(status, NT_STATUS_PROPSET_NOT_FOUND)) {
1508 status = NT_STATUS_OK;
1510 if (!NT_STATUS_IS_OK(status)) {
1511 return status;
1514 dom_sid_split_rid(mem_ctx, &group_sid, &dom_sid, &rid);
1516 map = talloc_zero(mem_ctx, GROUP_MAP);
1517 if (map == NULL) {
1518 status = NT_STATUS_NO_MEMORY;
1519 goto done;
1522 map->nt_name = talloc_strdup(map, sAMAccountName);
1523 if (map->nt_name == NULL) {
1524 status = NT_STATUS_NO_MEMORY;
1525 goto done;
1528 if (description) {
1529 map->comment = talloc_strdup(map, description);
1530 } else {
1531 map->comment = talloc_strdup(map, "");
1533 if (map->comment == NULL) {
1534 status = NT_STATUS_NO_MEMORY;
1535 goto done;
1538 sid_to_fstring(sid_string, &group_sid);
1539 DEBUG(0,("Creating alias[%s] - %s members[%u]\n",
1540 map->nt_name, sid_string, num_members));
1542 status = dssync_insert_obj(pctx, pctx->aliases, obj);
1543 if (!NT_STATUS_IS_OK(status)) {
1544 goto done;
1547 if (pdb_getgrsid(map, group_sid)) {
1548 if (map->gid != -1) {
1549 grp = getgrgid(map->gid);
1551 insert = false;
1554 if (grp == NULL) {
1555 gid_t gid;
1557 /* No group found from mapping, find it from its name. */
1558 if ((grp = getgrnam(map->nt_name)) == NULL) {
1560 /* No appropriate group found, create one */
1562 DEBUG(0, ("Creating unix group: '%s'\n",
1563 map->nt_name));
1565 if (smb_create_group(map->nt_name, &gid) != 0) {
1566 status = NT_STATUS_ACCESS_DENIED;
1567 goto done;
1570 if ((grp = getgrgid(gid)) == NULL) {
1571 status = NT_STATUS_ACCESS_DENIED;
1572 goto done;
1577 map->gid = grp->gr_gid;
1578 map->sid = group_sid;
1580 if (dom_sid_equal(dom_sid, &global_sid_Builtin)) {
1582 * pdb_ldap does not like SID_NAME_WKN_GRP...
1584 * map.sid_name_use = SID_NAME_WKN_GRP;
1586 map->sid_name_use = SID_NAME_ALIAS;
1587 } else {
1588 map->sid_name_use = SID_NAME_ALIAS;
1591 if (insert) {
1592 pdb_add_group_mapping_entry(map);
1593 } else {
1594 pdb_update_group_mapping_entry(map);
1597 for (i=0; i < num_members; i++) {
1598 struct dssync_passdb_mem *mem;
1600 status = dssync_create_mem(pctx, obj,
1601 true /* active */,
1602 &members[i], &mem);
1603 if (!NT_STATUS_IS_OK(status)) {
1604 goto done;
1608 status = NT_STATUS_OK;
1610 done:
1611 TALLOC_FREE(map);
1612 return status;
1615 /****************************************************************
1616 ****************************************************************/
1618 static NTSTATUS handle_group_object(struct dssync_passdb *pctx,
1619 TALLOC_CTX *mem_ctx,
1620 struct dssync_passdb_obj *obj)
1622 struct drsuapi_DsReplicaObjectListItemEx *cur = obj->cur;
1623 NTSTATUS status;
1624 struct group *grp = NULL;
1625 struct dom_sid group_sid;
1626 fstring sid_string;
1627 GROUP_MAP *map;
1628 bool insert = true;
1630 const char *sAMAccountName;
1631 uint32_t sAMAccountType;
1632 uint32_t groupType;
1633 const char *description;
1634 uint32_t i;
1635 uint32_t num_members = 0;
1636 struct drsuapi_DsReplicaObjectIdentifier3 *members = NULL;
1638 group_sid = cur->object.identifier->sid;
1639 GET_STRING_EX(sAMAccountName, true);
1640 GET_UINT32_EX(sAMAccountType, true);
1641 GET_UINT32_EX(groupType, true);
1642 GET_STRING(description);
1644 status = find_drsuapi_attr_dn(obj, cur, DRSUAPI_ATTID_member,
1645 &num_members, &members);
1646 if (NT_STATUS_EQUAL(status, NT_STATUS_PROPSET_NOT_FOUND)) {
1647 status = NT_STATUS_OK;
1649 if (!NT_STATUS_IS_OK(status)) {
1650 return status;
1653 map = talloc_zero(NULL, GROUP_MAP);
1654 if (!map) {
1655 return NT_STATUS_NO_MEMORY;
1658 map->nt_name = talloc_strdup(map, sAMAccountName);
1659 if (!map->nt_name) {
1660 status = NT_STATUS_NO_MEMORY;
1661 goto done;
1663 if (description) {
1664 map->comment = talloc_strdup(map, description);
1665 } else {
1666 map->comment = talloc_strdup(map, "");
1668 if (!map->comment) {
1669 status = NT_STATUS_NO_MEMORY;
1670 goto done;
1673 sid_to_fstring(sid_string, &group_sid);
1674 DEBUG(0,("Creating group[%s] - %s members [%u]\n",
1675 map->nt_name, sid_string, num_members));
1677 status = dssync_insert_obj(pctx, pctx->groups, obj);
1678 if (!NT_STATUS_IS_OK(status)) {
1679 goto done;
1682 if (pdb_getgrsid(map, group_sid)) {
1683 if (map->gid != -1) {
1684 grp = getgrgid(map->gid);
1686 insert = false;
1689 if (grp == NULL) {
1690 gid_t gid;
1692 /* No group found from mapping, find it from its name. */
1693 if ((grp = getgrnam(map->nt_name)) == NULL) {
1695 /* No appropriate group found, create one */
1697 DEBUG(0, ("Creating unix group: '%s'\n",
1698 map->nt_name));
1700 if (smb_create_group(map->nt_name, &gid) != 0) {
1701 status = NT_STATUS_ACCESS_DENIED;
1702 goto done;
1705 if ((grp = getgrnam(map->nt_name)) == NULL) {
1706 status = NT_STATUS_ACCESS_DENIED;
1707 goto done;
1712 map->gid = grp->gr_gid;
1713 map->sid = group_sid;
1714 map->sid_name_use = SID_NAME_DOM_GRP;
1716 if (insert) {
1717 pdb_add_group_mapping_entry(map);
1718 } else {
1719 pdb_update_group_mapping_entry(map);
1722 for (i=0; i < num_members; i++) {
1723 struct dssync_passdb_mem *mem;
1725 status = dssync_create_mem(pctx, obj,
1726 true /* active */,
1727 &members[i], &mem);
1728 if (!NT_STATUS_IS_OK(status)) {
1729 goto done;
1733 status = NT_STATUS_OK;
1735 done:
1736 TALLOC_FREE(map);
1737 return status;
1740 /****************************************************************
1741 ****************************************************************/
1743 static NTSTATUS handle_interdomain_trust_object(struct dssync_passdb *pctx,
1744 TALLOC_CTX *mem_ctx,
1745 struct dssync_passdb_obj *obj)
1747 struct drsuapi_DsReplicaObjectListItemEx *cur = obj->cur;
1748 DEBUG(0,("trust: %s\n", cur->object.identifier->dn));
1749 return NT_STATUS_NOT_IMPLEMENTED;
1752 /****************************************************************
1753 ****************************************************************/
1755 struct dssync_object_table_t {
1756 uint32_t type;
1757 NTSTATUS (*fn) (struct dssync_passdb *pctx,
1758 TALLOC_CTX *mem_ctx,
1759 struct dssync_passdb_obj *obj);
1762 static const struct dssync_object_table_t dssync_object_table[] = {
1763 { ATYPE_NORMAL_ACCOUNT, handle_account_object },
1764 { ATYPE_WORKSTATION_TRUST, handle_account_object },
1765 { ATYPE_SECURITY_LOCAL_GROUP, handle_alias_object },
1766 { ATYPE_SECURITY_GLOBAL_GROUP, handle_group_object },
1767 { ATYPE_INTERDOMAIN_TRUST, handle_interdomain_trust_object },
1770 /****************************************************************
1771 ****************************************************************/
1773 static NTSTATUS parse_object(struct dssync_passdb *pctx,
1774 TALLOC_CTX *mem_ctx,
1775 struct drsuapi_DsReplicaObjectListItemEx *cur)
1777 NTSTATUS status = NT_STATUS_OK;
1778 DATA_BLOB *blob;
1779 int i = 0;
1780 int a = 0;
1781 struct drsuapi_DsReplicaAttribute *attr;
1783 char *name = NULL;
1784 uint32_t uacc = 0;
1785 uint32_t sam_type = 0;
1787 DEBUG(3, ("parsing object '%s'\n", cur->object.identifier->dn));
1789 for (i=0; i < cur->object.attribute_ctr.num_attributes; i++) {
1791 attr = &cur->object.attribute_ctr.attributes[i];
1793 if (attr->value_ctr.num_values != 1) {
1794 continue;
1797 if (!attr->value_ctr.values[0].blob) {
1798 continue;
1801 blob = attr->value_ctr.values[0].blob;
1803 switch (attr->attid) {
1804 case DRSUAPI_ATTID_sAMAccountName:
1805 pull_string_talloc(mem_ctx, NULL, 0, &name,
1806 blob->data, blob->length,
1807 STR_UNICODE);
1808 break;
1809 case DRSUAPI_ATTID_sAMAccountType:
1810 sam_type = IVAL(blob->data, 0);
1811 break;
1812 case DRSUAPI_ATTID_userAccountControl:
1813 uacc = IVAL(blob->data, 0);
1814 break;
1815 default:
1816 break;
1820 for (a=0; a < ARRAY_SIZE(dssync_object_table); a++) {
1821 if (sam_type == dssync_object_table[a].type) {
1822 if (dssync_object_table[a].fn) {
1823 struct dssync_passdb_obj *obj;
1824 status = dssync_create_obj(pctx, pctx->all,
1825 sam_type, cur, &obj);
1826 if (!NT_STATUS_IS_OK(status)) {
1827 break;
1829 status = dssync_object_table[a].fn(pctx,
1830 mem_ctx,
1831 obj);
1832 break;
1837 return status;
1840 static NTSTATUS parse_link(struct dssync_passdb *pctx,
1841 TALLOC_CTX *mem_ctx,
1842 struct drsuapi_DsReplicaLinkedAttribute *cur)
1844 struct drsuapi_DsReplicaObjectIdentifier3 *id3;
1845 const DATA_BLOB *blob;
1846 enum ndr_err_code ndr_err;
1847 NTSTATUS status;
1848 bool active = false;
1849 struct dssync_passdb_mem *mem;
1850 struct dssync_passdb_obj *obj;
1852 if (cur->attid != DRSUAPI_ATTID_member) {
1853 return NT_STATUS_OK;
1856 if (cur->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE) {
1857 active = true;
1860 DEBUG(3, ("parsing link '%s' - %s\n",
1861 cur->identifier->dn, active?"adding":"deleting"));
1863 blob = cur->value.blob;
1865 if (blob == NULL) {
1866 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1869 obj = dssync_search_obj_by_guid(pctx, pctx->all, &cur->identifier->guid);
1870 if (obj == NULL) {
1871 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1874 id3 = talloc_zero(obj, struct drsuapi_DsReplicaObjectIdentifier3);
1875 if (id3 == NULL) {
1876 return NT_STATUS_NO_MEMORY;
1879 /* windows sometimes sends an extra two pad bytes here */
1880 ndr_err = ndr_pull_struct_blob(blob, id3, id3,
1881 (ndr_pull_flags_fn_t)ndr_pull_drsuapi_DsReplicaObjectIdentifier3);
1882 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1883 status = ndr_map_error2ntstatus(ndr_err);
1884 return status;
1887 status = dssync_create_mem(pctx, obj,
1888 active,
1889 id3, &mem);
1890 if (!NT_STATUS_IS_OK(status)) {
1891 return status;
1894 return NT_STATUS_OK;
1897 /****************************************************************
1898 ****************************************************************/
1900 static NTSTATUS passdb_process_objects(struct dssync_context *ctx,
1901 TALLOC_CTX *mem_ctx,
1902 struct drsuapi_DsReplicaObjectListItemEx *cur,
1903 struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr)
1905 NTSTATUS status = NT_STATUS_OK;
1906 struct dssync_passdb *pctx =
1907 talloc_get_type_abort(ctx->private_data,
1908 struct dssync_passdb);
1910 for (; cur; cur = cur->next_object) {
1911 status = parse_object(pctx, mem_ctx, cur);
1912 if (!NT_STATUS_IS_OK(status)) {
1913 goto out;
1917 out:
1918 return status;
1921 /****************************************************************
1922 ****************************************************************/
1924 static NTSTATUS passdb_process_links(struct dssync_context *ctx,
1925 TALLOC_CTX *mem_ctx,
1926 uint32_t count,
1927 struct drsuapi_DsReplicaLinkedAttribute *links,
1928 struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr)
1930 NTSTATUS status = NT_STATUS_OK;
1931 struct dssync_passdb *pctx =
1932 talloc_get_type_abort(ctx->private_data,
1933 struct dssync_passdb);
1934 uint32_t i;
1936 for (i = 0; i < count; i++) {
1937 status = parse_link(pctx, mem_ctx, &links[i]);
1938 if (!NT_STATUS_IS_OK(status)) {
1939 goto out;
1943 out:
1944 return status;
1947 /****************************************************************
1948 ****************************************************************/
1950 const struct dssync_ops libnet_dssync_passdb_ops = {
1951 .startup = passdb_startup,
1952 .process_objects = passdb_process_objects,
1953 .process_links = passdb_process_links,
1954 .finish = passdb_finish,