libnet: Add NULL checks to py_net_finddc
[Samba.git] / source3 / libnet / libnet_dssync_passdb.c
blob8e2a4593373c1dc8e6abfcb97bca3b16e3f68035
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"
31 #include "lib/util/base64.h"
33 /****************************************************************
34 ****************************************************************/
36 struct dssync_passdb {
37 struct pdb_methods *methods;
38 struct db_context *all;
39 struct db_context *aliases;
40 struct db_context *groups;
43 struct dssync_passdb_obj {
44 struct dssync_passdb_obj *self;
45 uint32_t type;
46 struct drsuapi_DsReplicaObjectListItemEx *cur;
47 TDB_DATA key;
48 TDB_DATA data;
49 struct db_context *members;
52 struct dssync_passdb_mem {
53 struct dssync_passdb_mem *self;
54 bool active;
55 struct drsuapi_DsReplicaObjectIdentifier3 *cur;
56 struct dssync_passdb_obj *obj;
57 TDB_DATA key;
58 TDB_DATA data;
61 static NTSTATUS dssync_insert_obj(struct dssync_passdb *pctx,
62 struct db_context *db,
63 struct dssync_passdb_obj *obj)
65 NTSTATUS status;
66 struct db_record *rec;
67 TDB_DATA value;
69 rec = dbwrap_fetch_locked(db, talloc_tos(), obj->key);
70 if (rec == NULL) {
71 return NT_STATUS_NO_MEMORY;
74 value = dbwrap_record_get_value(rec);
75 if (value.dsize != 0) {
76 abort();
79 status = dbwrap_record_store(rec, obj->data, TDB_INSERT);
80 if (!NT_STATUS_IS_OK(status)) {
81 TALLOC_FREE(rec);
82 return status;
84 TALLOC_FREE(rec);
85 return NT_STATUS_OK;
88 static struct dssync_passdb_obj *dssync_parse_obj(const TDB_DATA data)
90 struct dssync_passdb_obj *obj;
92 if (data.dsize != sizeof(obj)) {
93 return NULL;
97 * we need to copy the pointer to avoid alignment problems
98 * on some systems.
100 memcpy(&obj, data.dptr, sizeof(obj));
102 return talloc_get_type_abort(obj, struct dssync_passdb_obj);
105 static struct dssync_passdb_obj *dssync_search_obj_by_guid(struct dssync_passdb *pctx,
106 struct db_context *db,
107 const struct GUID *guid)
109 struct dssync_passdb_obj *obj;
110 TDB_DATA key;
111 TDB_DATA data;
112 NTSTATUS status;
114 key = make_tdb_data((const uint8_t *)(const void *)guid,
115 sizeof(*guid));
117 status = dbwrap_fetch(db, talloc_tos(), key, &data);
118 if (!NT_STATUS_IS_OK(status)) {
119 return NULL;
122 obj = dssync_parse_obj(data);
123 return obj;
126 static NTSTATUS dssync_create_obj(struct dssync_passdb *pctx,
127 struct db_context *db,
128 uint32_t type,
129 struct drsuapi_DsReplicaObjectListItemEx *cur,
130 struct dssync_passdb_obj **_obj)
132 NTSTATUS status;
133 struct dssync_passdb_obj *obj;
135 obj = talloc_zero(pctx, struct dssync_passdb_obj);
136 if (obj == NULL) {
137 return NT_STATUS_NO_MEMORY;
139 obj->self = obj;
140 obj->cur = cur;
141 obj->type = type;
142 obj->key = make_tdb_data((const uint8_t *)(void *)&cur->object.identifier->guid,
143 sizeof(cur->object.identifier->guid));
144 obj->data = make_tdb_data((const uint8_t *)(void *)&obj->self,
145 sizeof(obj->self));
147 obj->members = db_open_rbt(obj);
148 if (obj->members == NULL) {
149 return NT_STATUS_NO_MEMORY;
152 status = dssync_insert_obj(pctx, db, obj);
153 if (!NT_STATUS_IS_OK(status)) {
154 TALLOC_FREE(obj);
155 return status;
157 *_obj = obj;
158 return NT_STATUS_OK;
161 static NTSTATUS dssync_insert_mem(struct dssync_passdb *pctx,
162 struct dssync_passdb_obj *obj,
163 struct dssync_passdb_mem *mem)
165 NTSTATUS status;
166 struct db_record *rec;
167 TDB_DATA value;
169 rec = dbwrap_fetch_locked(obj->members, talloc_tos(), mem->key);
170 if (rec == NULL) {
171 return NT_STATUS_NO_MEMORY;
174 value = dbwrap_record_get_value(rec);
175 if (value.dsize != 0) {
176 abort();
179 status = dbwrap_record_store(rec, mem->data, TDB_INSERT);
180 if (!NT_STATUS_IS_OK(status)) {
181 TALLOC_FREE(rec);
182 return status;
184 TALLOC_FREE(rec);
185 return NT_STATUS_OK;
188 static NTSTATUS dssync_create_mem(struct dssync_passdb *pctx,
189 struct dssync_passdb_obj *obj,
190 bool active,
191 struct drsuapi_DsReplicaObjectIdentifier3 *cur,
192 struct dssync_passdb_mem **_mem)
194 NTSTATUS status;
195 struct dssync_passdb_mem *mem;
197 mem = talloc_zero(pctx, struct dssync_passdb_mem);
198 if (mem == NULL) {
199 return NT_STATUS_NO_MEMORY;
201 mem->self = mem;
202 mem->cur = cur;
203 mem->active = active;
204 mem->obj = NULL;
205 mem->key = make_tdb_data((const uint8_t *)(void *)&cur->guid,
206 sizeof(cur->guid));
207 mem->data = make_tdb_data((const uint8_t *)(void *)&mem->self,
208 sizeof(mem->self));
210 status = dssync_insert_mem(pctx, obj, mem);
211 if (!NT_STATUS_IS_OK(status)) {
212 TALLOC_FREE(obj);
213 return status;
215 *_mem = mem;
216 return NT_STATUS_OK;
219 static struct dssync_passdb_mem *dssync_parse_mem(const TDB_DATA data)
221 struct dssync_passdb_mem *mem;
223 if (data.dsize != sizeof(mem)) {
224 return NULL;
228 * we need to copy the pointer to avoid alignment problems
229 * on some systems.
231 memcpy(&mem, data.dptr, sizeof(mem));
233 return talloc_get_type_abort(mem, struct dssync_passdb_mem);
236 static NTSTATUS passdb_startup(struct dssync_context *ctx, TALLOC_CTX *mem_ctx,
237 struct replUpToDateVectorBlob **pold_utdv)
239 NTSTATUS status;
240 struct dssync_passdb *pctx;
242 pctx = talloc_zero(mem_ctx, struct dssync_passdb);
243 if (pctx == NULL) {
244 return NT_STATUS_NO_MEMORY;
247 if (ctx->output_filename) {
248 status = make_pdb_method_name(&pctx->methods, ctx->output_filename);
249 } else {
250 status = make_pdb_method_name(&pctx->methods, lp_passdb_backend());
253 if (!NT_STATUS_IS_OK(status)) {
254 return status;
257 pctx->all = db_open_rbt(pctx);
258 if (pctx->all == NULL) {
259 return NT_STATUS_NO_MEMORY;
261 pctx->aliases = db_open_rbt(pctx);
262 if (pctx->aliases == NULL) {
263 return NT_STATUS_NO_MEMORY;
265 pctx->groups = db_open_rbt(pctx);
266 if (pctx->groups == NULL) {
267 return NT_STATUS_NO_MEMORY;
270 ctx->private_data = pctx;
272 return status;
275 /****************************************************************
276 ****************************************************************/
278 struct dssync_passdb_traverse_amembers {
279 struct dssync_context *ctx;
280 struct dssync_passdb_obj *obj;
281 const char *name;
282 uint32_t idx;
285 struct dssync_passdb_traverse_aliases {
286 struct dssync_context *ctx;
287 const char *name;
288 uint32_t idx;
291 static int dssync_passdb_traverse_amembers(struct db_record *rec,
292 void *private_data)
294 struct dssync_passdb_traverse_amembers *state =
295 (struct dssync_passdb_traverse_amembers *)private_data;
296 struct dssync_passdb *pctx =
297 talloc_get_type_abort(state->ctx->private_data,
298 struct dssync_passdb);
299 struct dssync_passdb_mem *mem;
300 NTSTATUS status;
301 struct dom_sid alias_sid;
302 struct dom_sid member_sid;
303 const char *member_dn;
304 size_t num_members;
305 size_t i;
306 struct dom_sid *members;
307 bool is_member = false;
308 const char *action;
309 TDB_DATA value;
311 state->idx++;
313 alias_sid = state->obj->cur->object.identifier->sid;
315 value = dbwrap_record_get_value(rec);
316 mem = dssync_parse_mem(value);
317 if (mem == NULL) {
318 return -1;
321 member_sid = mem->cur->sid;
322 member_dn = mem->cur->dn;
324 mem->obj = dssync_search_obj_by_guid(pctx, pctx->all, &mem->cur->guid);
325 if (mem->obj == NULL) {
326 DEBUG(0,("alias[%s] member[%s] can't resolve member - ignoring\n",
327 sid_string_dbg(&alias_sid),
328 is_null_sid(&member_sid)?
329 sid_string_dbg(&member_sid):
330 member_dn));
331 return 0;
334 switch (mem->obj->type) {
335 case ATYPE_DISTRIBUTION_LOCAL_GROUP:
336 case ATYPE_DISTRIBUTION_GLOBAL_GROUP:
337 DEBUG(0, ("alias[%s] ignore distribution group [%s]\n",
338 sid_string_dbg(&alias_sid),
339 member_dn));
340 return 0;
341 default:
342 break;
345 DEBUG(0,("alias[%s] member[%s]\n",
346 sid_string_dbg(&alias_sid),
347 sid_string_dbg(&member_sid)));
349 status = pdb_enum_aliasmem(&alias_sid, talloc_tos(),
350 &members, &num_members);
351 if (!NT_STATUS_IS_OK(status)) {
352 DEBUG(0, ("Could not find current alias members %s - %s\n",
353 sid_string_dbg(&alias_sid),
354 nt_errstr(status)));
355 return -1;
358 for (i=0; i < num_members; i++) {
359 bool match;
361 match = dom_sid_equal(&members[i], &member_sid);
362 if (match) {
363 is_member = true;
364 break;
368 status = NT_STATUS_OK;
369 action = "none";
370 if (!is_member && mem->active) {
371 action = "add";
372 pdb_add_aliasmem(&alias_sid, &member_sid);
373 } else if (is_member && !mem->active) {
374 action = "delete";
375 pdb_del_aliasmem(&alias_sid, &member_sid);
377 if (!NT_STATUS_IS_OK(status)) {
378 DEBUG(0, ("Could not %s %s as alias members of %s - %s\n",
379 action,
380 sid_string_dbg(&member_sid),
381 sid_string_dbg(&alias_sid),
382 nt_errstr(status)));
383 return -1;
386 return 0;
389 static int dssync_passdb_traverse_aliases(struct db_record *rec,
390 void *private_data)
392 struct dssync_passdb_traverse_aliases *state =
393 (struct dssync_passdb_traverse_aliases *)private_data;
394 struct dssync_passdb *pctx =
395 talloc_get_type_abort(state->ctx->private_data,
396 struct dssync_passdb);
397 struct dssync_passdb_traverse_amembers mstate;
398 struct dssync_passdb_obj *obj;
399 TDB_DATA value;
400 NTSTATUS status;
402 state->idx++;
403 if (pctx->methods == NULL) {
404 return -1;
407 value = dbwrap_record_get_value(rec);
408 obj = dssync_parse_obj(value);
409 if (obj == NULL) {
410 return -1;
413 ZERO_STRUCT(mstate);
414 mstate.ctx = state->ctx;
415 mstate.name = "members";
416 mstate.obj = obj;
417 status = dbwrap_traverse_read(obj->members,
418 dssync_passdb_traverse_amembers,
419 &mstate, NULL);
420 if (!NT_STATUS_IS_OK(status)) {
421 return -1;
424 return 0;
427 struct dssync_passdb_traverse_gmembers {
428 struct dssync_context *ctx;
429 struct dssync_passdb_obj *obj;
430 const char *name;
431 uint32_t idx;
434 struct dssync_passdb_traverse_groups {
435 struct dssync_context *ctx;
436 const char *name;
437 uint32_t idx;
440 static int dssync_passdb_traverse_gmembers(struct db_record *rec,
441 void *private_data)
443 struct dssync_passdb_traverse_gmembers *state =
444 (struct dssync_passdb_traverse_gmembers *)private_data;
445 struct dssync_passdb *pctx =
446 talloc_get_type_abort(state->ctx->private_data,
447 struct dssync_passdb);
448 struct dssync_passdb_mem *mem;
449 NTSTATUS status;
450 char *nt_member = NULL;
451 char **unix_members;
452 struct dom_sid group_sid;
453 struct dom_sid member_sid;
454 struct samu *member = NULL;
455 const char *member_dn = NULL;
456 GROUP_MAP *map;
457 struct group *grp;
458 uint32_t rid;
459 bool is_unix_member = false;
460 TDB_DATA value;
462 state->idx++;
464 group_sid = state->obj->cur->object.identifier->sid;
466 status = dom_sid_split_rid(talloc_tos(), &group_sid, NULL, &rid);
467 if (!NT_STATUS_IS_OK(status)) {
468 return -1;
471 value = dbwrap_record_get_value(rec);
473 mem = dssync_parse_mem(value);
474 if (mem == NULL) {
475 return -1;
478 member_sid = mem->cur->sid;
479 member_dn = mem->cur->dn;
481 mem->obj = dssync_search_obj_by_guid(pctx, pctx->all, &mem->cur->guid);
482 if (mem->obj == NULL) {
483 DEBUG(0,("group[%s] member[%s] can't resolve member - ignoring\n",
484 sid_string_dbg(&group_sid),
485 is_null_sid(&member_sid)?
486 sid_string_dbg(&member_sid):
487 member_dn));
488 return 0;
491 member_sid = mem->obj->cur->object.identifier->sid;
492 member_dn = mem->obj->cur->object.identifier->dn;
494 switch (mem->obj->type) {
495 case ATYPE_SECURITY_LOCAL_GROUP:
496 case ATYPE_SECURITY_GLOBAL_GROUP:
497 DEBUG(0, ("Group[%s] ignore member group [%s]\n",
498 sid_string_dbg(&group_sid),
499 sid_string_dbg(&member_sid)));
500 return 0;
502 case ATYPE_DISTRIBUTION_LOCAL_GROUP:
503 case ATYPE_DISTRIBUTION_GLOBAL_GROUP:
504 DEBUG(0, ("Group[%s] ignore distribution group [%s]\n",
505 sid_string_dbg(&group_sid),
506 member_dn));
507 return 0;
508 default:
509 break;
512 map = talloc_zero(NULL, GROUP_MAP);
513 if (!map) {
514 return -1;
517 if (!get_domain_group_from_sid(group_sid, map)) {
518 DEBUG(0, ("Could not find global group %s\n",
519 sid_string_dbg(&group_sid)));
520 //return NT_STATUS_NO_SUCH_GROUP;
521 TALLOC_FREE(map);
522 return -1;
525 if (!(grp = getgrgid(map->gid))) {
526 DEBUG(0, ("Could not find unix group %lu\n",
527 (unsigned long)map->gid));
528 //return NT_STATUS_NO_SUCH_GROUP;
529 TALLOC_FREE(map);
530 return -1;
533 TALLOC_FREE(map);
535 DEBUG(0,("Group members of %s: ", grp->gr_name));
537 if ( !(member = samu_new(talloc_tos())) ) {
538 //return NT_STATUS_NO_MEMORY;
539 return -1;
542 if (!pdb_getsampwsid(member, &member_sid)) {
543 DEBUG(1, ("Found bogus group member: (member_sid=%s group=%s)\n",
544 sid_string_tos(&member_sid), grp->gr_name));
545 TALLOC_FREE(member);
546 return -1;
549 if (pdb_get_group_rid(member) == rid) {
550 DEBUGADD(0,("%s(primary),", pdb_get_username(member)));
551 TALLOC_FREE(member);
552 return -1;
555 DEBUGADD(0,("%s,", pdb_get_username(member)));
556 nt_member = talloc_strdup(talloc_tos(), pdb_get_username(member));
557 TALLOC_FREE(member);
559 DEBUGADD(0,("\n"));
561 unix_members = grp->gr_mem;
563 while (*unix_members) {
564 if (strcmp(*unix_members, nt_member) == 0) {
565 is_unix_member = true;
566 break;
568 unix_members += 1;
571 if (!is_unix_member && mem->active) {
572 smb_add_user_group(grp->gr_name, nt_member);
573 } else if (is_unix_member && !mem->active) {
574 smb_delete_user_group(grp->gr_name, nt_member);
577 return 0;
580 static int dssync_passdb_traverse_groups(struct db_record *rec,
581 void *private_data)
583 struct dssync_passdb_traverse_groups *state =
584 (struct dssync_passdb_traverse_groups *)private_data;
585 struct dssync_passdb *pctx =
586 talloc_get_type_abort(state->ctx->private_data,
587 struct dssync_passdb);
588 struct dssync_passdb_traverse_gmembers mstate;
589 struct dssync_passdb_obj *obj;
590 TDB_DATA value;
591 NTSTATUS status;
593 state->idx++;
594 if (pctx->methods == NULL) {
595 return -1;
598 value = dbwrap_record_get_value(rec);
600 obj = dssync_parse_obj(value);
601 if (obj == NULL) {
602 return -1;
605 ZERO_STRUCT(mstate);
606 mstate.ctx = state->ctx;
607 mstate.name = "members";
608 mstate.obj = obj;
609 status = dbwrap_traverse_read(obj->members,
610 dssync_passdb_traverse_gmembers,
611 &mstate, NULL);
612 if (!NT_STATUS_IS_OK(status)) {
613 return -1;
616 return 0;
619 static NTSTATUS passdb_finish(struct dssync_context *ctx, TALLOC_CTX *mem_ctx,
620 struct replUpToDateVectorBlob *new_utdv)
622 struct dssync_passdb *pctx =
623 talloc_get_type_abort(ctx->private_data,
624 struct dssync_passdb);
625 struct dssync_passdb_traverse_aliases astate;
626 struct dssync_passdb_traverse_groups gstate;
627 NTSTATUS status;
629 ZERO_STRUCT(astate);
630 astate.ctx = ctx;
631 astate.name = "aliases";
632 status = dbwrap_traverse_read(pctx->aliases,
633 dssync_passdb_traverse_aliases,
634 &astate, NULL);
635 if (!NT_STATUS_IS_OK(status)) {
636 return NT_STATUS_INTERNAL_ERROR;
639 ZERO_STRUCT(gstate);
640 gstate.ctx = ctx;
641 gstate.name = "groups";
642 status = dbwrap_traverse_read(pctx->groups,
643 dssync_passdb_traverse_groups,
644 &gstate, NULL);
645 if (!NT_STATUS_IS_OK(status)) {
646 return NT_STATUS_INTERNAL_ERROR;
649 TALLOC_FREE(pctx->methods);
650 TALLOC_FREE(pctx);
652 return NT_STATUS_OK;
655 /****************************************************************
656 ****************************************************************/
658 static NTSTATUS smb_create_user(TALLOC_CTX *mem_ctx,
659 uint32_t acct_flags,
660 const char *account,
661 struct passwd **passwd_p)
663 struct passwd *passwd;
664 char *add_script = NULL;
666 passwd = Get_Pwnam_alloc(mem_ctx, account);
667 if (passwd) {
668 *passwd_p = passwd;
669 return NT_STATUS_OK;
672 /* Create appropriate user */
673 if (acct_flags & ACB_NORMAL) {
674 add_script = lp_add_user_script(mem_ctx);
675 } else if ( (acct_flags & ACB_WSTRUST) ||
676 (acct_flags & ACB_SVRTRUST) ||
677 (acct_flags & ACB_DOMTRUST) ) {
678 add_script = lp_add_machine_script(mem_ctx);
679 } else {
680 DEBUG(1, ("Unknown user type: %s\n",
681 pdb_encode_acct_ctrl(acct_flags, NEW_PW_FORMAT_SPACE_PADDED_LEN)));
682 return NT_STATUS_UNSUCCESSFUL;
685 if (!add_script) {
686 return NT_STATUS_NO_MEMORY;
689 if (*add_script) {
690 int add_ret;
691 add_script = talloc_all_string_sub(mem_ctx, add_script,
692 "%u", account);
693 if (!add_script) {
694 return NT_STATUS_NO_MEMORY;
696 add_ret = smbrun(add_script, NULL, NULL);
697 DEBUG(add_ret ? 0 : 1,("fetch_account: Running the command `%s' "
698 "gave %d\n", add_script, add_ret));
699 if (add_ret == 0) {
700 smb_nscd_flush_user_cache();
704 /* try and find the possible unix account again */
705 passwd = Get_Pwnam_alloc(mem_ctx, account);
706 if (!passwd) {
707 return NT_STATUS_NO_SUCH_USER;
710 *passwd_p = passwd;
712 return NT_STATUS_OK;
715 static struct drsuapi_DsReplicaAttribute *find_drsuapi_attr(
716 const struct drsuapi_DsReplicaObjectListItemEx *cur,
717 uint32_t attid)
719 int i = 0;
721 for (i = 0; i < cur->object.attribute_ctr.num_attributes; i++) {
722 struct drsuapi_DsReplicaAttribute *attr;
724 attr = &cur->object.attribute_ctr.attributes[i];
726 if (attr->attid == attid) {
727 return attr;
731 return NULL;
734 static NTSTATUS find_drsuapi_attr_string(TALLOC_CTX *mem_ctx,
735 const struct drsuapi_DsReplicaObjectListItemEx *cur,
736 uint32_t attid,
737 uint32_t *_count,
738 char ***_array)
740 struct drsuapi_DsReplicaAttribute *attr;
741 char **array;
742 uint32_t a;
744 attr = find_drsuapi_attr(cur, attid);
745 if (attr == NULL) {
746 return NT_STATUS_PROPSET_NOT_FOUND;
749 array = talloc_array(mem_ctx, char *, attr->value_ctr.num_values);
750 if (array == NULL) {
751 return NT_STATUS_NO_MEMORY;
754 for (a = 0; a < attr->value_ctr.num_values; a++) {
755 const DATA_BLOB *blob;
756 ssize_t ret;
758 blob = attr->value_ctr.values[a].blob;
760 if (blob == NULL) {
761 return NT_STATUS_INTERNAL_DB_CORRUPTION;
764 ret = pull_string_talloc(array, NULL, 0, &array[a],
765 blob->data, blob->length,
766 STR_UNICODE);
767 if (ret == -1) {
768 //TODO
769 return NT_STATUS_INTERNAL_ERROR;
773 *_count = attr->value_ctr.num_values;
774 *_array = array;
775 return NT_STATUS_OK;
778 static NTSTATUS find_drsuapi_attr_int32(TALLOC_CTX *mem_ctx,
779 const struct drsuapi_DsReplicaObjectListItemEx *cur,
780 uint32_t attid,
781 uint32_t *_count,
782 int32_t **_array)
784 struct drsuapi_DsReplicaAttribute *attr;
785 int32_t *array;
786 uint32_t a;
788 attr = find_drsuapi_attr(cur, attid);
789 if (attr == NULL) {
790 return NT_STATUS_PROPSET_NOT_FOUND;
793 array = talloc_array(mem_ctx, int32_t, attr->value_ctr.num_values);
794 if (array == NULL) {
795 return NT_STATUS_NO_MEMORY;
798 for (a = 0; a < attr->value_ctr.num_values; a++) {
799 const DATA_BLOB *blob;
801 blob = attr->value_ctr.values[a].blob;
803 if (blob == NULL) {
804 return NT_STATUS_INTERNAL_DB_CORRUPTION;
807 if (blob->length != 4) {
808 return NT_STATUS_INTERNAL_DB_CORRUPTION;
811 array[a] = IVAL(blob->data, 0);
814 *_count = attr->value_ctr.num_values;
815 *_array = array;
816 return NT_STATUS_OK;
819 static NTSTATUS find_drsuapi_attr_blob(TALLOC_CTX *mem_ctx,
820 const struct drsuapi_DsReplicaObjectListItemEx *cur,
821 uint32_t attid,
822 uint32_t *_count,
823 DATA_BLOB **_array)
825 struct drsuapi_DsReplicaAttribute *attr;
826 DATA_BLOB *array;
827 uint32_t a;
829 attr = find_drsuapi_attr(cur, attid);
830 if (attr == NULL) {
831 return NT_STATUS_PROPSET_NOT_FOUND;
834 array = talloc_array(mem_ctx, DATA_BLOB, attr->value_ctr.num_values);
835 if (array == NULL) {
836 return NT_STATUS_NO_MEMORY;
839 for (a = 0; a < attr->value_ctr.num_values; a++) {
840 const DATA_BLOB *blob;
842 blob = attr->value_ctr.values[a].blob;
844 if (blob == NULL) {
845 return NT_STATUS_INTERNAL_DB_CORRUPTION;
848 array[a] = data_blob_talloc(array, blob->data, blob->length);
849 if (array[a].length != blob->length) {
850 return NT_STATUS_NO_MEMORY;
853 *_count = attr->value_ctr.num_values;
854 *_array = array;
855 return NT_STATUS_OK;
858 static NTSTATUS find_drsuapi_attr_int64(TALLOC_CTX *mem_ctx,
859 const struct drsuapi_DsReplicaObjectListItemEx *cur,
860 uint32_t attid,
861 uint32_t *_count,
862 int64_t **_array)
864 struct drsuapi_DsReplicaAttribute *attr;
865 int64_t *array;
866 uint32_t a;
868 attr = find_drsuapi_attr(cur, attid);
869 if (attr == NULL) {
870 return NT_STATUS_PROPSET_NOT_FOUND;
873 array = talloc_array(mem_ctx, int64_t, attr->value_ctr.num_values);
874 if (array == NULL) {
875 return NT_STATUS_NO_MEMORY;
878 for (a = 0; a < attr->value_ctr.num_values; a++) {
879 const DATA_BLOB *blob;
881 blob = attr->value_ctr.values[a].blob;
883 if (blob == NULL) {
884 return NT_STATUS_INTERNAL_DB_CORRUPTION;
887 if (blob->length != 8) {
888 return NT_STATUS_INTERNAL_DB_CORRUPTION;
891 array[a] = BVAL(blob->data, 0);
893 *_count = attr->value_ctr.num_values;
894 *_array = array;
895 return NT_STATUS_OK;
898 static NTSTATUS find_drsuapi_attr_dn(TALLOC_CTX *mem_ctx,
899 const struct drsuapi_DsReplicaObjectListItemEx *cur,
900 uint32_t attid,
901 uint32_t *_count,
902 struct drsuapi_DsReplicaObjectIdentifier3 **_array)
904 struct drsuapi_DsReplicaAttribute *attr;
905 struct drsuapi_DsReplicaObjectIdentifier3 *array;
906 uint32_t a;
908 attr = find_drsuapi_attr(cur, attid);
909 if (attr == NULL) {
910 return NT_STATUS_PROPSET_NOT_FOUND;
913 array = talloc_array(mem_ctx,
914 struct drsuapi_DsReplicaObjectIdentifier3,
915 attr->value_ctr.num_values);
916 if (array == NULL) {
917 return NT_STATUS_NO_MEMORY;
920 for (a = 0; a < attr->value_ctr.num_values; a++) {
921 const DATA_BLOB *blob;
922 enum ndr_err_code ndr_err;
923 NTSTATUS status;
925 blob = attr->value_ctr.values[a].blob;
927 if (blob == NULL) {
928 return NT_STATUS_INTERNAL_DB_CORRUPTION;
931 /* windows sometimes sends an extra two pad bytes here */
932 ndr_err = ndr_pull_struct_blob(blob, array, &array[a],
933 (ndr_pull_flags_fn_t)ndr_pull_drsuapi_DsReplicaObjectIdentifier3);
934 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
935 status = ndr_map_error2ntstatus(ndr_err);
936 return status;
939 *_count = attr->value_ctr.num_values;
940 *_array = array;
941 return NT_STATUS_OK;
944 #define GET_BLOB_EX(attr, needed) do { \
945 NTSTATUS _status; \
946 uint32_t _cnt; \
947 DATA_BLOB *_vals = NULL; \
948 attr = data_blob_null; \
949 _status = find_drsuapi_attr_blob(mem_ctx, cur, \
950 DRSUAPI_ATTID_ ## attr, \
951 &_cnt, &_vals); \
952 if (NT_STATUS_EQUAL(_status, NT_STATUS_PROPSET_NOT_FOUND)) { \
953 if (!needed) { \
954 _status = NT_STATUS_OK; \
955 _cnt = 0; \
958 if (!NT_STATUS_IS_OK(_status)) { \
959 DEBUG(0,(__location__ "attr[%s] %s\n", \
960 #attr, nt_errstr(_status))); \
961 return _status; \
963 if (_cnt == 0) { \
964 if (needed) { \
965 talloc_free(_vals); \
966 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
967 return NT_STATUS_OBJECT_NAME_NOT_FOUND; \
969 } else if (_cnt > 1) { \
970 talloc_free(_vals); \
971 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
972 return NT_STATUS_INTERNAL_DB_CORRUPTION; \
973 } else { \
974 attr = _vals[0]; \
975 (void)talloc_steal(mem_ctx, _vals[0].data); \
977 talloc_free(_vals); \
978 } while(0)
980 #define GET_STRING_EX(attr, needed) do { \
981 NTSTATUS _status; \
982 uint32_t _cnt; \
983 char **_vals = NULL; \
984 attr = NULL; \
985 _status = find_drsuapi_attr_string(mem_ctx, cur, \
986 DRSUAPI_ATTID_ ## attr, \
987 &_cnt, &_vals); \
988 if (NT_STATUS_EQUAL(_status, NT_STATUS_PROPSET_NOT_FOUND)) { \
989 if (!needed) { \
990 _status = NT_STATUS_OK; \
991 _cnt = 0; \
994 if (!NT_STATUS_IS_OK(_status)) { \
995 DEBUG(0,(__location__ "attr[%s] %s\n", \
996 #attr, nt_errstr(_status))); \
997 return _status; \
999 if (_cnt == 0) { \
1000 if (needed) { \
1001 talloc_free(_vals); \
1002 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1003 return NT_STATUS_OBJECT_NAME_NOT_FOUND; \
1005 } else if (_cnt > 1) { \
1006 talloc_free(_vals); \
1007 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1008 return NT_STATUS_INTERNAL_DB_CORRUPTION; \
1009 } else { \
1010 attr = talloc_move(mem_ctx, &_vals[0]); \
1012 talloc_free(_vals); \
1013 } while(0)
1015 #define GET_UINT32_EX(attr, needed) do { \
1016 NTSTATUS _status; \
1017 uint32_t _cnt; \
1018 int32_t*_vals = NULL; \
1019 attr = 0; \
1020 _status = find_drsuapi_attr_int32(mem_ctx, cur, \
1021 DRSUAPI_ATTID_ ## attr, \
1022 &_cnt, &_vals); \
1023 if (NT_STATUS_EQUAL(_status, NT_STATUS_PROPSET_NOT_FOUND)) { \
1024 if (!needed) { \
1025 _status = NT_STATUS_OK; \
1026 _cnt = 0; \
1029 if (!NT_STATUS_IS_OK(_status)) { \
1030 DEBUG(0,(__location__ "attr[%s] %s\n", \
1031 #attr, nt_errstr(_status))); \
1032 return _status; \
1034 if (_cnt == 0) { \
1035 if (needed) { \
1036 talloc_free(_vals); \
1037 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1038 return NT_STATUS_OBJECT_NAME_NOT_FOUND; \
1040 } else if (_cnt > 1) { \
1041 talloc_free(_vals); \
1042 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1043 return NT_STATUS_INTERNAL_DB_CORRUPTION; \
1044 } else { \
1045 attr = (uint32_t)_vals[0]; \
1047 talloc_free(_vals); \
1048 } while(0)
1050 #define GET_UINT64_EX(attr, needed) do { \
1051 NTSTATUS _status; \
1052 uint32_t _cnt; \
1053 int64_t *_vals = NULL; \
1054 attr = 0; \
1055 _status = find_drsuapi_attr_int64(mem_ctx, cur, \
1056 DRSUAPI_ATTID_ ## attr, \
1057 &_cnt, &_vals); \
1058 if (NT_STATUS_EQUAL(_status, NT_STATUS_PROPSET_NOT_FOUND)) { \
1059 if (!needed) { \
1060 _status = NT_STATUS_OK; \
1061 _cnt = 0; \
1064 if (!NT_STATUS_IS_OK(_status)) { \
1065 DEBUG(0,(__location__ "attr[%s] %s\n", \
1066 #attr, nt_errstr(_status))); \
1067 return _status; \
1069 if (_cnt == 0) { \
1070 if (needed) { \
1071 talloc_free(_vals); \
1072 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1073 return NT_STATUS_OBJECT_NAME_NOT_FOUND; \
1075 } else if (_cnt > 1) { \
1076 talloc_free(_vals); \
1077 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1078 return NT_STATUS_INTERNAL_DB_CORRUPTION; \
1079 } else { \
1080 attr = (uint64_t)_vals[0]; \
1082 talloc_free(_vals); \
1083 } while(0)
1085 #define GET_BLOB(attr) GET_BLOB_EX(attr, false)
1086 #define GET_STRING(attr) GET_STRING_EX(attr, false)
1087 #define GET_UINT32(attr) GET_UINT32_EX(attr, false)
1088 #define GET_UINT64(attr) GET_UINT64_EX(attr, false)
1090 /* Convert a struct samu_DELTA to a struct samu. */
1091 #define STRING_CHANGED (old_string && !new_string) ||\
1092 (!old_string && new_string) ||\
1093 (old_string && new_string && (strcmp(old_string, new_string) != 0))
1095 #define STRING_CHANGED_NC(s1,s2) ((s1) && !(s2)) ||\
1096 (!(s1) && (s2)) ||\
1097 ((s1) && (s2) && (strcmp((s1), (s2)) != 0))
1099 /****************************************************************
1100 ****************************************************************/
1102 static NTSTATUS sam_account_from_object(struct samu *account,
1103 struct drsuapi_DsReplicaObjectListItemEx *cur)
1105 TALLOC_CTX *mem_ctx = account;
1106 const char *old_string, *new_string;
1107 time_t unix_time, stored_time;
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 DATA_BLOB userParameters;
1123 struct dom_sid objectSid;
1124 uint32_t primaryGroupID;
1125 uint32_t userAccountControl;
1126 DATA_BLOB logonHours;
1127 uint32_t badPwdCount;
1128 uint32_t logonCount;
1129 DATA_BLOB unicodePwd;
1130 DATA_BLOB dBCSPwd;
1132 uint32_t rid = 0;
1133 uint32_t acct_flags;
1134 uint32_t units_per_week;
1136 objectSid = cur->object.identifier->sid;
1137 GET_STRING_EX(sAMAccountName, true);
1138 DEBUG(0,("sam_account_from_object(%s, %s) start\n",
1139 sAMAccountName, sid_string_dbg(&objectSid)));
1140 GET_UINT64(lastLogon);
1141 GET_UINT64(lastLogoff);
1142 GET_UINT64(pwdLastSet);
1143 GET_UINT64(accountExpires);
1144 GET_STRING(displayName);
1145 GET_STRING(homeDirectory);
1146 GET_STRING(homeDrive);
1147 GET_STRING(scriptPath);
1148 GET_STRING(profilePath);
1149 GET_STRING(description);
1150 GET_STRING(userWorkstations);
1151 GET_BLOB(userParameters);
1152 GET_UINT32(primaryGroupID);
1153 GET_UINT32(userAccountControl);
1154 GET_BLOB(logonHours);
1155 GET_UINT32(badPwdCount);
1156 GET_UINT32(logonCount);
1157 GET_BLOB(unicodePwd);
1158 GET_BLOB(dBCSPwd);
1160 status = dom_sid_split_rid(mem_ctx, &objectSid, NULL, &rid);
1161 if (!NT_STATUS_IS_OK(status)) {
1162 return status;
1164 acct_flags = ds_uf2acb(userAccountControl);
1166 /* Username, fullname, home dir, dir drive, logon script, acct
1167 desc, workstations, profile. */
1169 if (sAMAccountName) {
1170 old_string = pdb_get_nt_username(account);
1171 new_string = sAMAccountName;
1173 if (STRING_CHANGED) {
1174 pdb_set_nt_username(account, new_string, PDB_CHANGED);
1177 /* Unix username is the same - for sanity */
1178 old_string = pdb_get_username( account );
1179 if (STRING_CHANGED) {
1180 pdb_set_username(account, new_string, PDB_CHANGED);
1184 if (displayName) {
1185 old_string = pdb_get_fullname(account);
1186 new_string = displayName;
1188 if (STRING_CHANGED)
1189 pdb_set_fullname(account, new_string, PDB_CHANGED);
1192 if (homeDirectory) {
1193 old_string = pdb_get_homedir(account);
1194 new_string = homeDirectory;
1196 if (STRING_CHANGED)
1197 pdb_set_homedir(account, new_string, PDB_CHANGED);
1200 if (homeDrive) {
1201 old_string = pdb_get_dir_drive(account);
1202 new_string = homeDrive;
1204 if (STRING_CHANGED)
1205 pdb_set_dir_drive(account, new_string, PDB_CHANGED);
1208 if (scriptPath) {
1209 old_string = pdb_get_logon_script(account);
1210 new_string = scriptPath;
1212 if (STRING_CHANGED)
1213 pdb_set_logon_script(account, new_string, PDB_CHANGED);
1216 if (description) {
1217 old_string = pdb_get_acct_desc(account);
1218 new_string = description;
1220 if (STRING_CHANGED)
1221 pdb_set_acct_desc(account, new_string, PDB_CHANGED);
1224 if (userWorkstations) {
1225 old_string = pdb_get_workstations(account);
1226 new_string = userWorkstations;
1228 if (STRING_CHANGED)
1229 pdb_set_workstations(account, new_string, PDB_CHANGED);
1232 if (profilePath) {
1233 old_string = pdb_get_profile_path(account);
1234 new_string = profilePath;
1236 if (STRING_CHANGED)
1237 pdb_set_profile_path(account, new_string, PDB_CHANGED);
1240 if (userParameters.data) {
1241 char *newstr = NULL;
1242 old_string = pdb_get_munged_dial(account);
1244 if (userParameters.length != 0) {
1245 newstr = base64_encode_data_blob(talloc_tos(),
1246 userParameters);
1247 SMB_ASSERT(newstr != NULL);
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 && !all_zero(dBCSPwd.data, 16)) {
1330 pdb_set_lanman_passwd(account, dBCSPwd.data, PDB_CHANGED);
1333 if (unicodePwd.length == 16 && !all_zero(unicodePwd.data, 16)) {
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 userAccountControl;
1372 user_sid = cur->object.identifier->sid;
1373 GET_STRING_EX(sAMAccountName, true);
1374 GET_UINT32_EX(userAccountControl, true);
1376 status = dom_sid_split_rid(mem_ctx, &user_sid, NULL, &rid);
1377 if (!NT_STATUS_IS_OK(status)) {
1378 return status;
1381 fstrcpy(account, sAMAccountName);
1382 if (rid == DOMAIN_RID_GUEST) {
1384 * pdb_getsampwsid() has special handling for DOMAIN_RID_GUEST
1385 * that's why we need to ignore it here.
1387 * pdb_smbpasswd.c also has some DOMAIN_RID_GUEST related
1388 * code...
1390 DEBUG(0,("Ignore %s - %s\n", account, sid_string_dbg(&user_sid)));
1391 return NT_STATUS_OK;
1393 DEBUG(0,("Creating account: %s\n", account));
1395 if ( !(sam_account = samu_new(mem_ctx)) ) {
1396 return NT_STATUS_NO_MEMORY;
1399 acct_flags = ds_uf2acb(userAccountControl);
1400 status = smb_create_user(sam_account, acct_flags, account, &passwd);
1401 if (!NT_STATUS_IS_OK(status)) {
1402 DEBUG(0,("Could not create posix account info for '%s'- %s\n",
1403 account, nt_errstr(status)));
1404 TALLOC_FREE(sam_account);
1405 return status;
1408 DEBUG(3, ("Attempting to find SID %s for user %s in the passdb\n",
1409 sid_string_dbg(&user_sid), account));
1410 if (!pdb_getsampwsid(sam_account, &user_sid)) {
1411 sam_account_from_object(sam_account, cur);
1412 DEBUG(3, ("Attempting to add user SID %s for user %s in the passdb\n",
1413 sid_string_dbg(&user_sid),
1414 pdb_get_username(sam_account)));
1415 if (!NT_STATUS_IS_OK(pdb_add_sam_account(sam_account))) {
1416 DEBUG(1, ("SAM Account for %s failed to be added to the passdb!\n",
1417 account));
1418 TALLOC_FREE(sam_account);
1419 return NT_STATUS_ACCESS_DENIED;
1421 } else {
1422 sam_account_from_object(sam_account, cur);
1423 DEBUG(3, ("Attempting to update user SID %s for user %s in the passdb\n",
1424 sid_string_dbg(&user_sid),
1425 pdb_get_username(sam_account)));
1426 if (!NT_STATUS_IS_OK(pdb_update_sam_account(sam_account))) {
1427 DEBUG(1, ("SAM Account for %s failed to be updated in the passdb!\n",
1428 account));
1429 TALLOC_FREE(sam_account);
1430 return NT_STATUS_ACCESS_DENIED;
1434 if (pdb_get_group_sid(sam_account) == NULL) {
1435 TALLOC_FREE(sam_account);
1436 return NT_STATUS_UNSUCCESSFUL;
1439 group_sid = *pdb_get_group_sid(sam_account);
1441 map = talloc_zero(NULL, GROUP_MAP);
1442 if (!map) {
1443 return NT_STATUS_NO_MEMORY;
1446 if (!pdb_getgrsid(map, group_sid)) {
1447 DEBUG(0, ("Primary group of %s has no mapping!\n",
1448 pdb_get_username(sam_account)));
1449 } else {
1450 if (map->gid != passwd->pw_gid) {
1451 if (!(grp = getgrgid(map->gid))) {
1452 DEBUG(0, ("Could not find unix group %lu for user %s (group SID=%s)\n",
1453 (unsigned long)map->gid, pdb_get_username(sam_account),
1454 sid_string_dbg(&group_sid)));
1455 } else {
1456 smb_set_primary_group(grp->gr_name, pdb_get_username(sam_account));
1461 TALLOC_FREE(map);
1463 if ( !passwd ) {
1464 DEBUG(1, ("No unix user for this account (%s), cannot adjust mappings\n",
1465 pdb_get_username(sam_account)));
1468 TALLOC_FREE(sam_account);
1469 return NT_STATUS_OK;
1472 /****************************************************************
1473 ****************************************************************/
1475 static NTSTATUS handle_alias_object(struct dssync_passdb *pctx,
1476 TALLOC_CTX *mem_ctx,
1477 struct dssync_passdb_obj *obj)
1479 struct drsuapi_DsReplicaObjectListItemEx *cur = obj->cur;
1480 NTSTATUS status;
1481 struct group *grp = NULL;
1482 struct dom_sid group_sid;
1483 uint32_t rid = 0;
1484 struct dom_sid *dom_sid = NULL;
1485 fstring sid_string;
1486 GROUP_MAP *map;
1487 bool insert = true;
1489 const char *sAMAccountName;
1490 const char *description;
1491 uint32_t i;
1492 uint32_t num_members = 0;
1493 struct drsuapi_DsReplicaObjectIdentifier3 *members = NULL;
1495 group_sid = cur->object.identifier->sid;
1496 GET_STRING_EX(sAMAccountName, true);
1497 GET_STRING(description);
1499 status = find_drsuapi_attr_dn(obj, cur, DRSUAPI_ATTID_member,
1500 &num_members, &members);
1501 if (NT_STATUS_EQUAL(status, NT_STATUS_PROPSET_NOT_FOUND)) {
1502 status = NT_STATUS_OK;
1504 if (!NT_STATUS_IS_OK(status)) {
1505 return status;
1508 dom_sid_split_rid(mem_ctx, &group_sid, &dom_sid, &rid);
1510 map = talloc_zero(mem_ctx, GROUP_MAP);
1511 if (map == NULL) {
1512 status = NT_STATUS_NO_MEMORY;
1513 goto done;
1516 map->nt_name = talloc_strdup(map, sAMAccountName);
1517 if (map->nt_name == NULL) {
1518 status = NT_STATUS_NO_MEMORY;
1519 goto done;
1522 if (description) {
1523 map->comment = talloc_strdup(map, description);
1524 } else {
1525 map->comment = talloc_strdup(map, "");
1527 if (map->comment == NULL) {
1528 status = NT_STATUS_NO_MEMORY;
1529 goto done;
1532 sid_to_fstring(sid_string, &group_sid);
1533 DEBUG(0,("Creating alias[%s] - %s members[%u]\n",
1534 map->nt_name, sid_string, num_members));
1536 status = dssync_insert_obj(pctx, pctx->aliases, obj);
1537 if (!NT_STATUS_IS_OK(status)) {
1538 goto done;
1541 if (pdb_getgrsid(map, group_sid)) {
1542 if (map->gid != -1) {
1543 grp = getgrgid(map->gid);
1545 insert = false;
1548 if (grp == NULL) {
1549 gid_t gid;
1551 /* No group found from mapping, find it from its name. */
1552 if ((grp = getgrnam(map->nt_name)) == NULL) {
1554 /* No appropriate group found, create one */
1556 DEBUG(0, ("Creating unix group: '%s'\n",
1557 map->nt_name));
1559 if (smb_create_group(map->nt_name, &gid) != 0) {
1560 status = NT_STATUS_ACCESS_DENIED;
1561 goto done;
1564 if ((grp = getgrgid(gid)) == NULL) {
1565 status = NT_STATUS_ACCESS_DENIED;
1566 goto done;
1571 map->gid = grp->gr_gid;
1572 map->sid = group_sid;
1574 if (dom_sid_equal(dom_sid, &global_sid_Builtin)) {
1576 * pdb_ldap does not like SID_NAME_WKN_GRP...
1578 * map.sid_name_use = SID_NAME_WKN_GRP;
1580 map->sid_name_use = SID_NAME_ALIAS;
1581 } else {
1582 map->sid_name_use = SID_NAME_ALIAS;
1585 if (insert) {
1586 pdb_add_group_mapping_entry(map);
1587 } else {
1588 pdb_update_group_mapping_entry(map);
1591 for (i=0; i < num_members; i++) {
1592 struct dssync_passdb_mem *mem;
1594 status = dssync_create_mem(pctx, obj,
1595 true /* active */,
1596 &members[i], &mem);
1597 if (!NT_STATUS_IS_OK(status)) {
1598 goto done;
1602 status = NT_STATUS_OK;
1604 done:
1605 TALLOC_FREE(map);
1606 return status;
1609 /****************************************************************
1610 ****************************************************************/
1612 static NTSTATUS handle_group_object(struct dssync_passdb *pctx,
1613 TALLOC_CTX *mem_ctx,
1614 struct dssync_passdb_obj *obj)
1616 struct drsuapi_DsReplicaObjectListItemEx *cur = obj->cur;
1617 NTSTATUS status;
1618 struct group *grp = NULL;
1619 struct dom_sid group_sid;
1620 fstring sid_string;
1621 GROUP_MAP *map;
1622 bool insert = true;
1624 const char *sAMAccountName;
1625 const char *description;
1626 uint32_t i;
1627 uint32_t num_members = 0;
1628 struct drsuapi_DsReplicaObjectIdentifier3 *members = NULL;
1630 group_sid = cur->object.identifier->sid;
1631 GET_STRING_EX(sAMAccountName, true);
1632 GET_STRING(description);
1634 status = find_drsuapi_attr_dn(obj, cur, DRSUAPI_ATTID_member,
1635 &num_members, &members);
1636 if (NT_STATUS_EQUAL(status, NT_STATUS_PROPSET_NOT_FOUND)) {
1637 status = NT_STATUS_OK;
1639 if (!NT_STATUS_IS_OK(status)) {
1640 return status;
1643 map = talloc_zero(NULL, GROUP_MAP);
1644 if (!map) {
1645 return NT_STATUS_NO_MEMORY;
1648 map->nt_name = talloc_strdup(map, sAMAccountName);
1649 if (!map->nt_name) {
1650 status = NT_STATUS_NO_MEMORY;
1651 goto done;
1653 if (description) {
1654 map->comment = talloc_strdup(map, description);
1655 } else {
1656 map->comment = talloc_strdup(map, "");
1658 if (!map->comment) {
1659 status = NT_STATUS_NO_MEMORY;
1660 goto done;
1663 sid_to_fstring(sid_string, &group_sid);
1664 DEBUG(0,("Creating group[%s] - %s members [%u]\n",
1665 map->nt_name, sid_string, num_members));
1667 status = dssync_insert_obj(pctx, pctx->groups, obj);
1668 if (!NT_STATUS_IS_OK(status)) {
1669 goto done;
1672 if (pdb_getgrsid(map, group_sid)) {
1673 if (map->gid != -1) {
1674 grp = getgrgid(map->gid);
1676 insert = false;
1679 if (grp == NULL) {
1680 gid_t gid;
1682 /* No group found from mapping, find it from its name. */
1683 if ((grp = getgrnam(map->nt_name)) == NULL) {
1685 /* No appropriate group found, create one */
1687 DEBUG(0, ("Creating unix group: '%s'\n",
1688 map->nt_name));
1690 if (smb_create_group(map->nt_name, &gid) != 0) {
1691 status = NT_STATUS_ACCESS_DENIED;
1692 goto done;
1695 if ((grp = getgrnam(map->nt_name)) == NULL) {
1696 status = NT_STATUS_ACCESS_DENIED;
1697 goto done;
1702 map->gid = grp->gr_gid;
1703 map->sid = group_sid;
1704 map->sid_name_use = SID_NAME_DOM_GRP;
1706 if (insert) {
1707 pdb_add_group_mapping_entry(map);
1708 } else {
1709 pdb_update_group_mapping_entry(map);
1712 for (i=0; i < num_members; i++) {
1713 struct dssync_passdb_mem *mem;
1715 status = dssync_create_mem(pctx, obj,
1716 true /* active */,
1717 &members[i], &mem);
1718 if (!NT_STATUS_IS_OK(status)) {
1719 goto done;
1723 status = NT_STATUS_OK;
1725 done:
1726 TALLOC_FREE(map);
1727 return status;
1730 /****************************************************************
1731 ****************************************************************/
1733 static NTSTATUS handle_interdomain_trust_object(struct dssync_passdb *pctx,
1734 TALLOC_CTX *mem_ctx,
1735 struct dssync_passdb_obj *obj)
1737 struct drsuapi_DsReplicaObjectListItemEx *cur = obj->cur;
1738 DEBUG(0,("trust: %s\n", cur->object.identifier->dn));
1739 return NT_STATUS_NOT_IMPLEMENTED;
1742 /****************************************************************
1743 ****************************************************************/
1745 struct dssync_object_table_t {
1746 uint32_t type;
1747 NTSTATUS (*fn) (struct dssync_passdb *pctx,
1748 TALLOC_CTX *mem_ctx,
1749 struct dssync_passdb_obj *obj);
1752 static const struct dssync_object_table_t dssync_object_table[] = {
1753 { ATYPE_NORMAL_ACCOUNT, handle_account_object },
1754 { ATYPE_WORKSTATION_TRUST, handle_account_object },
1755 { ATYPE_SECURITY_LOCAL_GROUP, handle_alias_object },
1756 { ATYPE_SECURITY_GLOBAL_GROUP, handle_group_object },
1757 { ATYPE_INTERDOMAIN_TRUST, handle_interdomain_trust_object },
1760 /****************************************************************
1761 ****************************************************************/
1763 static NTSTATUS parse_object(struct dssync_passdb *pctx,
1764 TALLOC_CTX *mem_ctx,
1765 struct drsuapi_DsReplicaObjectListItemEx *cur)
1767 NTSTATUS status = NT_STATUS_OK;
1768 DATA_BLOB *blob;
1769 int i = 0;
1770 int a = 0;
1771 struct drsuapi_DsReplicaAttribute *attr;
1773 char *name = NULL;
1774 uint32_t sam_type = 0;
1776 DEBUG(3, ("parsing object '%s'\n", cur->object.identifier->dn));
1778 for (i=0; i < cur->object.attribute_ctr.num_attributes; i++) {
1780 attr = &cur->object.attribute_ctr.attributes[i];
1782 if (attr->value_ctr.num_values != 1) {
1783 continue;
1786 if (!attr->value_ctr.values[0].blob) {
1787 continue;
1790 blob = attr->value_ctr.values[0].blob;
1792 switch (attr->attid) {
1793 case DRSUAPI_ATTID_sAMAccountName:
1794 pull_string_talloc(mem_ctx, NULL, 0, &name,
1795 blob->data, blob->length,
1796 STR_UNICODE);
1797 break;
1798 case DRSUAPI_ATTID_sAMAccountType:
1799 sam_type = IVAL(blob->data, 0);
1800 break;
1801 default:
1802 break;
1806 for (a=0; a < ARRAY_SIZE(dssync_object_table); a++) {
1807 if (sam_type == dssync_object_table[a].type) {
1808 if (dssync_object_table[a].fn) {
1809 struct dssync_passdb_obj *obj = NULL;
1810 status = dssync_create_obj(pctx, pctx->all,
1811 sam_type, cur, &obj);
1812 if (!NT_STATUS_IS_OK(status)) {
1813 break;
1815 status = dssync_object_table[a].fn(pctx,
1816 mem_ctx,
1817 obj);
1818 break;
1823 return status;
1826 static NTSTATUS parse_link(struct dssync_passdb *pctx,
1827 TALLOC_CTX *mem_ctx,
1828 struct drsuapi_DsReplicaLinkedAttribute *cur)
1830 struct drsuapi_DsReplicaObjectIdentifier3 *id3;
1831 const DATA_BLOB *blob;
1832 enum ndr_err_code ndr_err;
1833 NTSTATUS status;
1834 bool active = false;
1835 struct dssync_passdb_mem *mem;
1836 struct dssync_passdb_obj *obj;
1838 if (cur->attid != DRSUAPI_ATTID_member) {
1839 return NT_STATUS_OK;
1842 if (cur->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE) {
1843 active = true;
1846 DEBUG(3, ("parsing link '%s' - %s\n",
1847 cur->identifier->dn, active?"adding":"deleting"));
1849 blob = cur->value.blob;
1851 if (blob == NULL) {
1852 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1855 obj = dssync_search_obj_by_guid(pctx, pctx->all, &cur->identifier->guid);
1856 if (obj == NULL) {
1857 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1860 id3 = talloc_zero(obj, struct drsuapi_DsReplicaObjectIdentifier3);
1861 if (id3 == NULL) {
1862 return NT_STATUS_NO_MEMORY;
1865 /* windows sometimes sends an extra two pad bytes here */
1866 ndr_err = ndr_pull_struct_blob(blob, id3, id3,
1867 (ndr_pull_flags_fn_t)ndr_pull_drsuapi_DsReplicaObjectIdentifier3);
1868 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1869 status = ndr_map_error2ntstatus(ndr_err);
1870 return status;
1873 status = dssync_create_mem(pctx, obj,
1874 active,
1875 id3, &mem);
1876 if (!NT_STATUS_IS_OK(status)) {
1877 return status;
1880 return NT_STATUS_OK;
1883 /****************************************************************
1884 ****************************************************************/
1886 static NTSTATUS passdb_process_objects(struct dssync_context *ctx,
1887 TALLOC_CTX *mem_ctx,
1888 struct drsuapi_DsReplicaObjectListItemEx *cur,
1889 struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr)
1891 NTSTATUS status = NT_STATUS_OK;
1892 struct dssync_passdb *pctx =
1893 talloc_get_type_abort(ctx->private_data,
1894 struct dssync_passdb);
1896 for (; cur; cur = cur->next_object) {
1897 status = parse_object(pctx, mem_ctx, cur);
1898 if (!NT_STATUS_IS_OK(status)) {
1899 goto out;
1903 out:
1904 return status;
1907 /****************************************************************
1908 ****************************************************************/
1910 static NTSTATUS passdb_process_links(struct dssync_context *ctx,
1911 TALLOC_CTX *mem_ctx,
1912 uint32_t count,
1913 struct drsuapi_DsReplicaLinkedAttribute *links,
1914 struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr)
1916 NTSTATUS status = NT_STATUS_OK;
1917 struct dssync_passdb *pctx =
1918 talloc_get_type_abort(ctx->private_data,
1919 struct dssync_passdb);
1920 uint32_t i;
1922 for (i = 0; i < count; i++) {
1923 status = parse_link(pctx, mem_ctx, &links[i]);
1924 if (!NT_STATUS_IS_OK(status)) {
1925 goto out;
1929 out:
1930 return status;
1933 /****************************************************************
1934 ****************************************************************/
1936 const struct dssync_ops libnet_dssync_passdb_ops = {
1937 .startup = passdb_startup,
1938 .process_objects = passdb_process_objects,
1939 .process_links = passdb_process_links,
1940 .finish = passdb_finish,