bootstrap: We can only build docker images on gitlab shared runners
[Samba.git] / source3 / libnet / libnet_dssync_passdb.c
blob4b559f15e7531d669f84186d194184f5ac148b46
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 struct dom_sid_buf buf1, buf2;
304 const char *member_dn;
305 size_t num_members;
306 size_t i;
307 struct dom_sid *members;
308 bool is_member = false;
309 const char *action;
310 TDB_DATA value;
312 state->idx++;
314 alias_sid = state->obj->cur->object.identifier->sid;
316 value = dbwrap_record_get_value(rec);
317 mem = dssync_parse_mem(value);
318 if (mem == NULL) {
319 return -1;
322 member_sid = mem->cur->sid;
323 member_dn = mem->cur->dn;
325 mem->obj = dssync_search_obj_by_guid(pctx, pctx->all, &mem->cur->guid);
326 if (mem->obj == NULL) {
327 DEBUG(0,("alias[%s] member[%s] can't resolve member - ignoring\n",
328 dom_sid_str_buf(&alias_sid, &buf1),
329 is_null_sid(&member_sid)?
330 dom_sid_str_buf(&member_sid, &buf2):
331 member_dn));
332 return 0;
335 switch (mem->obj->type) {
336 case ATYPE_DISTRIBUTION_LOCAL_GROUP:
337 case ATYPE_DISTRIBUTION_GLOBAL_GROUP:
338 DEBUG(0, ("alias[%s] ignore distribution group [%s]\n",
339 dom_sid_str_buf(&alias_sid, &buf1),
340 member_dn));
341 return 0;
342 default:
343 break;
346 DEBUG(0,("alias[%s] member[%s]\n",
347 dom_sid_str_buf(&alias_sid, &buf1),
348 dom_sid_str_buf(&member_sid, &buf2)));
350 status = pdb_enum_aliasmem(&alias_sid, talloc_tos(),
351 &members, &num_members);
352 if (!NT_STATUS_IS_OK(status)) {
353 DEBUG(0, ("Could not find current alias members %s - %s\n",
354 dom_sid_str_buf(&alias_sid, &buf1),
355 nt_errstr(status)));
356 return -1;
359 for (i=0; i < num_members; i++) {
360 bool match;
362 match = dom_sid_equal(&members[i], &member_sid);
363 if (match) {
364 is_member = true;
365 break;
369 status = NT_STATUS_OK;
370 action = "none";
371 if (!is_member && mem->active) {
372 action = "add";
373 pdb_add_aliasmem(&alias_sid, &member_sid);
374 } else if (is_member && !mem->active) {
375 action = "delete";
376 pdb_del_aliasmem(&alias_sid, &member_sid);
378 if (!NT_STATUS_IS_OK(status)) {
379 DEBUG(0, ("Could not %s %s as alias members of %s - %s\n",
380 action,
381 dom_sid_str_buf(&member_sid, &buf1),
382 dom_sid_str_buf(&alias_sid, &buf2),
383 nt_errstr(status)));
384 return -1;
387 return 0;
390 static int dssync_passdb_traverse_aliases(struct db_record *rec,
391 void *private_data)
393 struct dssync_passdb_traverse_aliases *state =
394 (struct dssync_passdb_traverse_aliases *)private_data;
395 struct dssync_passdb *pctx =
396 talloc_get_type_abort(state->ctx->private_data,
397 struct dssync_passdb);
398 struct dssync_passdb_traverse_amembers mstate;
399 struct dssync_passdb_obj *obj;
400 TDB_DATA value;
401 NTSTATUS status;
403 state->idx++;
404 if (pctx->methods == NULL) {
405 return -1;
408 value = dbwrap_record_get_value(rec);
409 obj = dssync_parse_obj(value);
410 if (obj == NULL) {
411 return -1;
414 ZERO_STRUCT(mstate);
415 mstate.ctx = state->ctx;
416 mstate.name = "members";
417 mstate.obj = obj;
418 status = dbwrap_traverse_read(obj->members,
419 dssync_passdb_traverse_amembers,
420 &mstate, NULL);
421 if (!NT_STATUS_IS_OK(status)) {
422 return -1;
425 return 0;
428 struct dssync_passdb_traverse_gmembers {
429 struct dssync_context *ctx;
430 struct dssync_passdb_obj *obj;
431 const char *name;
432 uint32_t idx;
435 struct dssync_passdb_traverse_groups {
436 struct dssync_context *ctx;
437 const char *name;
438 uint32_t idx;
441 static int dssync_passdb_traverse_gmembers(struct db_record *rec,
442 void *private_data)
444 struct dssync_passdb_traverse_gmembers *state =
445 (struct dssync_passdb_traverse_gmembers *)private_data;
446 struct dssync_passdb *pctx =
447 talloc_get_type_abort(state->ctx->private_data,
448 struct dssync_passdb);
449 struct dssync_passdb_mem *mem;
450 NTSTATUS status;
451 char *nt_member = NULL;
452 char **unix_members;
453 struct dom_sid group_sid;
454 struct dom_sid member_sid;
455 struct dom_sid_buf buf1, buf2;
456 struct samu *member = NULL;
457 const char *member_dn = NULL;
458 GROUP_MAP *map;
459 struct group *grp;
460 uint32_t rid;
461 bool is_unix_member = false;
462 TDB_DATA value;
464 state->idx++;
466 group_sid = state->obj->cur->object.identifier->sid;
468 status = dom_sid_split_rid(talloc_tos(), &group_sid, NULL, &rid);
469 if (!NT_STATUS_IS_OK(status)) {
470 return -1;
473 value = dbwrap_record_get_value(rec);
475 mem = dssync_parse_mem(value);
476 if (mem == NULL) {
477 return -1;
480 member_sid = mem->cur->sid;
481 member_dn = mem->cur->dn;
483 mem->obj = dssync_search_obj_by_guid(pctx, pctx->all, &mem->cur->guid);
484 if (mem->obj == NULL) {
485 DEBUG(0,("group[%s] member[%s] can't resolve member - ignoring\n",
486 dom_sid_str_buf(&group_sid, &buf1),
487 is_null_sid(&member_sid)?
488 dom_sid_str_buf(&member_sid, &buf2):
489 member_dn));
490 return 0;
493 member_sid = mem->obj->cur->object.identifier->sid;
494 member_dn = mem->obj->cur->object.identifier->dn;
496 switch (mem->obj->type) {
497 case ATYPE_SECURITY_LOCAL_GROUP:
498 case ATYPE_SECURITY_GLOBAL_GROUP:
499 DEBUG(0, ("Group[%s] ignore member group [%s]\n",
500 dom_sid_str_buf(&group_sid, &buf1),
501 dom_sid_str_buf(&member_sid, &buf2)));
502 return 0;
504 case ATYPE_DISTRIBUTION_LOCAL_GROUP:
505 case ATYPE_DISTRIBUTION_GLOBAL_GROUP:
506 DEBUG(0, ("Group[%s] ignore distribution group [%s]\n",
507 dom_sid_str_buf(&group_sid, &buf1),
508 member_dn));
509 return 0;
510 default:
511 break;
514 map = talloc_zero(NULL, GROUP_MAP);
515 if (!map) {
516 return -1;
519 if (!get_domain_group_from_sid(group_sid, map)) {
520 DEBUG(0, ("Could not find global group %s\n",
521 dom_sid_str_buf(&group_sid, &buf1)));
522 //return NT_STATUS_NO_SUCH_GROUP;
523 TALLOC_FREE(map);
524 return -1;
527 if (!(grp = getgrgid(map->gid))) {
528 DEBUG(0, ("Could not find unix group %lu\n",
529 (unsigned long)map->gid));
530 //return NT_STATUS_NO_SUCH_GROUP;
531 TALLOC_FREE(map);
532 return -1;
535 TALLOC_FREE(map);
537 DEBUG(0,("Group members of %s: ", grp->gr_name));
539 if ( !(member = samu_new(talloc_tos())) ) {
540 //return NT_STATUS_NO_MEMORY;
541 return -1;
544 if (!pdb_getsampwsid(member, &member_sid)) {
545 DEBUG(1, ("Found bogus group member: (member_sid=%s group=%s)\n",
546 dom_sid_str_buf(&member_sid, &buf1),
547 grp->gr_name));
548 TALLOC_FREE(member);
549 return -1;
552 if (pdb_get_group_rid(member) == rid) {
553 DEBUGADD(0,("%s(primary),", pdb_get_username(member)));
554 TALLOC_FREE(member);
555 return -1;
558 DEBUGADD(0,("%s,", pdb_get_username(member)));
559 nt_member = talloc_strdup(talloc_tos(), pdb_get_username(member));
560 TALLOC_FREE(member);
562 DEBUGADD(0,("\n"));
564 unix_members = grp->gr_mem;
566 while (*unix_members) {
567 if (strcmp(*unix_members, nt_member) == 0) {
568 is_unix_member = true;
569 break;
571 unix_members += 1;
574 if (!is_unix_member && mem->active) {
575 smb_add_user_group(grp->gr_name, nt_member);
576 } else if (is_unix_member && !mem->active) {
577 smb_delete_user_group(grp->gr_name, nt_member);
580 return 0;
583 static int dssync_passdb_traverse_groups(struct db_record *rec,
584 void *private_data)
586 struct dssync_passdb_traverse_groups *state =
587 (struct dssync_passdb_traverse_groups *)private_data;
588 struct dssync_passdb *pctx =
589 talloc_get_type_abort(state->ctx->private_data,
590 struct dssync_passdb);
591 struct dssync_passdb_traverse_gmembers mstate;
592 struct dssync_passdb_obj *obj;
593 TDB_DATA value;
594 NTSTATUS status;
596 state->idx++;
597 if (pctx->methods == NULL) {
598 return -1;
601 value = dbwrap_record_get_value(rec);
603 obj = dssync_parse_obj(value);
604 if (obj == NULL) {
605 return -1;
608 ZERO_STRUCT(mstate);
609 mstate.ctx = state->ctx;
610 mstate.name = "members";
611 mstate.obj = obj;
612 status = dbwrap_traverse_read(obj->members,
613 dssync_passdb_traverse_gmembers,
614 &mstate, NULL);
615 if (!NT_STATUS_IS_OK(status)) {
616 return -1;
619 return 0;
622 static NTSTATUS passdb_finish(struct dssync_context *ctx, TALLOC_CTX *mem_ctx,
623 struct replUpToDateVectorBlob *new_utdv)
625 struct dssync_passdb *pctx =
626 talloc_get_type_abort(ctx->private_data,
627 struct dssync_passdb);
628 struct dssync_passdb_traverse_aliases astate;
629 struct dssync_passdb_traverse_groups gstate;
630 NTSTATUS status;
632 ZERO_STRUCT(astate);
633 astate.ctx = ctx;
634 astate.name = "aliases";
635 status = dbwrap_traverse_read(pctx->aliases,
636 dssync_passdb_traverse_aliases,
637 &astate, NULL);
638 if (!NT_STATUS_IS_OK(status)) {
639 return NT_STATUS_INTERNAL_ERROR;
642 ZERO_STRUCT(gstate);
643 gstate.ctx = ctx;
644 gstate.name = "groups";
645 status = dbwrap_traverse_read(pctx->groups,
646 dssync_passdb_traverse_groups,
647 &gstate, NULL);
648 if (!NT_STATUS_IS_OK(status)) {
649 return NT_STATUS_INTERNAL_ERROR;
652 TALLOC_FREE(pctx->methods);
653 TALLOC_FREE(pctx);
655 return NT_STATUS_OK;
658 /****************************************************************
659 ****************************************************************/
661 static NTSTATUS smb_create_user(TALLOC_CTX *mem_ctx,
662 uint32_t acct_flags,
663 const char *account,
664 struct passwd **passwd_p)
666 struct passwd *passwd;
667 char *add_script = NULL;
669 passwd = Get_Pwnam_alloc(mem_ctx, account);
670 if (passwd) {
671 *passwd_p = passwd;
672 return NT_STATUS_OK;
675 /* Create appropriate user */
676 if (acct_flags & ACB_NORMAL) {
677 add_script = lp_add_user_script(mem_ctx);
678 } else if ( (acct_flags & ACB_WSTRUST) ||
679 (acct_flags & ACB_SVRTRUST) ||
680 (acct_flags & ACB_DOMTRUST) ) {
681 add_script = lp_add_machine_script(mem_ctx);
682 } else {
683 DEBUG(1, ("Unknown user type: %s\n",
684 pdb_encode_acct_ctrl(acct_flags, NEW_PW_FORMAT_SPACE_PADDED_LEN)));
685 return NT_STATUS_UNSUCCESSFUL;
688 if (!add_script) {
689 return NT_STATUS_NO_MEMORY;
692 if (*add_script) {
693 int add_ret;
694 add_script = talloc_all_string_sub(mem_ctx, add_script,
695 "%u", account);
696 if (!add_script) {
697 return NT_STATUS_NO_MEMORY;
699 add_ret = smbrun(add_script, NULL, NULL);
700 DEBUG(add_ret ? 0 : 1,("fetch_account: Running the command `%s' "
701 "gave %d\n", add_script, add_ret));
702 if (add_ret == 0) {
703 smb_nscd_flush_user_cache();
707 /* try and find the possible unix account again */
708 passwd = Get_Pwnam_alloc(mem_ctx, account);
709 if (!passwd) {
710 return NT_STATUS_NO_SUCH_USER;
713 *passwd_p = passwd;
715 return NT_STATUS_OK;
718 static struct drsuapi_DsReplicaAttribute *find_drsuapi_attr(
719 const struct drsuapi_DsReplicaObjectListItemEx *cur,
720 uint32_t attid)
722 int i = 0;
724 for (i = 0; i < cur->object.attribute_ctr.num_attributes; i++) {
725 struct drsuapi_DsReplicaAttribute *attr;
727 attr = &cur->object.attribute_ctr.attributes[i];
729 if (attr->attid == attid) {
730 return attr;
734 return NULL;
737 static NTSTATUS find_drsuapi_attr_string(TALLOC_CTX *mem_ctx,
738 const struct drsuapi_DsReplicaObjectListItemEx *cur,
739 uint32_t attid,
740 uint32_t *_count,
741 char ***_array)
743 struct drsuapi_DsReplicaAttribute *attr;
744 char **array;
745 uint32_t a;
747 attr = find_drsuapi_attr(cur, attid);
748 if (attr == NULL) {
749 return NT_STATUS_PROPSET_NOT_FOUND;
752 array = talloc_array(mem_ctx, char *, attr->value_ctr.num_values);
753 if (array == NULL) {
754 return NT_STATUS_NO_MEMORY;
757 for (a = 0; a < attr->value_ctr.num_values; a++) {
758 const DATA_BLOB *blob;
759 ssize_t ret;
761 blob = attr->value_ctr.values[a].blob;
763 if (blob == NULL) {
764 return NT_STATUS_INTERNAL_DB_CORRUPTION;
767 ret = pull_string_talloc(array, NULL, 0, &array[a],
768 blob->data, blob->length,
769 STR_UNICODE);
770 if (ret == -1) {
771 //TODO
772 return NT_STATUS_INTERNAL_ERROR;
776 *_count = attr->value_ctr.num_values;
777 *_array = array;
778 return NT_STATUS_OK;
781 static NTSTATUS find_drsuapi_attr_int32(TALLOC_CTX *mem_ctx,
782 const struct drsuapi_DsReplicaObjectListItemEx *cur,
783 uint32_t attid,
784 uint32_t *_count,
785 int32_t **_array)
787 struct drsuapi_DsReplicaAttribute *attr;
788 int32_t *array;
789 uint32_t a;
791 attr = find_drsuapi_attr(cur, attid);
792 if (attr == NULL) {
793 return NT_STATUS_PROPSET_NOT_FOUND;
796 array = talloc_array(mem_ctx, int32_t, attr->value_ctr.num_values);
797 if (array == NULL) {
798 return NT_STATUS_NO_MEMORY;
801 for (a = 0; a < attr->value_ctr.num_values; a++) {
802 const DATA_BLOB *blob;
804 blob = attr->value_ctr.values[a].blob;
806 if (blob == NULL) {
807 return NT_STATUS_INTERNAL_DB_CORRUPTION;
810 if (blob->length != 4) {
811 return NT_STATUS_INTERNAL_DB_CORRUPTION;
814 array[a] = IVAL(blob->data, 0);
817 *_count = attr->value_ctr.num_values;
818 *_array = array;
819 return NT_STATUS_OK;
822 static NTSTATUS find_drsuapi_attr_blob(TALLOC_CTX *mem_ctx,
823 const struct drsuapi_DsReplicaObjectListItemEx *cur,
824 uint32_t attid,
825 uint32_t *_count,
826 DATA_BLOB **_array)
828 struct drsuapi_DsReplicaAttribute *attr;
829 DATA_BLOB *array;
830 uint32_t a;
832 attr = find_drsuapi_attr(cur, attid);
833 if (attr == NULL) {
834 return NT_STATUS_PROPSET_NOT_FOUND;
837 array = talloc_array(mem_ctx, DATA_BLOB, attr->value_ctr.num_values);
838 if (array == NULL) {
839 return NT_STATUS_NO_MEMORY;
842 for (a = 0; a < attr->value_ctr.num_values; a++) {
843 const DATA_BLOB *blob;
845 blob = attr->value_ctr.values[a].blob;
847 if (blob == NULL) {
848 return NT_STATUS_INTERNAL_DB_CORRUPTION;
851 array[a] = data_blob_talloc(array, blob->data, blob->length);
852 if (array[a].length != blob->length) {
853 return NT_STATUS_NO_MEMORY;
856 *_count = attr->value_ctr.num_values;
857 *_array = array;
858 return NT_STATUS_OK;
861 static NTSTATUS find_drsuapi_attr_int64(TALLOC_CTX *mem_ctx,
862 const struct drsuapi_DsReplicaObjectListItemEx *cur,
863 uint32_t attid,
864 uint32_t *_count,
865 int64_t **_array)
867 struct drsuapi_DsReplicaAttribute *attr;
868 int64_t *array;
869 uint32_t a;
871 attr = find_drsuapi_attr(cur, attid);
872 if (attr == NULL) {
873 return NT_STATUS_PROPSET_NOT_FOUND;
876 array = talloc_array(mem_ctx, int64_t, attr->value_ctr.num_values);
877 if (array == NULL) {
878 return NT_STATUS_NO_MEMORY;
881 for (a = 0; a < attr->value_ctr.num_values; a++) {
882 const DATA_BLOB *blob;
884 blob = attr->value_ctr.values[a].blob;
886 if (blob == NULL) {
887 return NT_STATUS_INTERNAL_DB_CORRUPTION;
890 if (blob->length != 8) {
891 return NT_STATUS_INTERNAL_DB_CORRUPTION;
894 array[a] = BVAL(blob->data, 0);
896 *_count = attr->value_ctr.num_values;
897 *_array = array;
898 return NT_STATUS_OK;
901 static NTSTATUS find_drsuapi_attr_dn(TALLOC_CTX *mem_ctx,
902 const struct drsuapi_DsReplicaObjectListItemEx *cur,
903 uint32_t attid,
904 uint32_t *_count,
905 struct drsuapi_DsReplicaObjectIdentifier3 **_array)
907 struct drsuapi_DsReplicaAttribute *attr;
908 struct drsuapi_DsReplicaObjectIdentifier3 *array;
909 uint32_t a;
911 attr = find_drsuapi_attr(cur, attid);
912 if (attr == NULL) {
913 return NT_STATUS_PROPSET_NOT_FOUND;
916 array = talloc_array(mem_ctx,
917 struct drsuapi_DsReplicaObjectIdentifier3,
918 attr->value_ctr.num_values);
919 if (array == NULL) {
920 return NT_STATUS_NO_MEMORY;
923 for (a = 0; a < attr->value_ctr.num_values; a++) {
924 const DATA_BLOB *blob;
925 enum ndr_err_code ndr_err;
926 NTSTATUS status;
928 blob = attr->value_ctr.values[a].blob;
930 if (blob == NULL) {
931 return NT_STATUS_INTERNAL_DB_CORRUPTION;
934 /* windows sometimes sends an extra two pad bytes here */
935 ndr_err = ndr_pull_struct_blob(blob, array, &array[a],
936 (ndr_pull_flags_fn_t)ndr_pull_drsuapi_DsReplicaObjectIdentifier3);
937 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
938 status = ndr_map_error2ntstatus(ndr_err);
939 return status;
942 *_count = attr->value_ctr.num_values;
943 *_array = array;
944 return NT_STATUS_OK;
947 #define GET_BLOB_EX(attr, needed) do { \
948 NTSTATUS _status; \
949 uint32_t _cnt; \
950 DATA_BLOB *_vals = NULL; \
951 attr = data_blob_null; \
952 _status = find_drsuapi_attr_blob(mem_ctx, cur, \
953 DRSUAPI_ATTID_ ## attr, \
954 &_cnt, &_vals); \
955 if (NT_STATUS_EQUAL(_status, NT_STATUS_PROPSET_NOT_FOUND)) { \
956 if (!needed) { \
957 _status = NT_STATUS_OK; \
958 _cnt = 0; \
961 if (!NT_STATUS_IS_OK(_status)) { \
962 DEBUG(0,(__location__ "attr[%s] %s\n", \
963 #attr, nt_errstr(_status))); \
964 return _status; \
966 if (_cnt == 0) { \
967 if (needed) { \
968 talloc_free(_vals); \
969 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
970 return NT_STATUS_OBJECT_NAME_NOT_FOUND; \
972 } else if (_cnt > 1) { \
973 talloc_free(_vals); \
974 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
975 return NT_STATUS_INTERNAL_DB_CORRUPTION; \
976 } else { \
977 attr = _vals[0]; \
978 (void)talloc_steal(mem_ctx, _vals[0].data); \
980 talloc_free(_vals); \
981 } while(0)
983 #define GET_STRING_EX(attr, needed) do { \
984 NTSTATUS _status; \
985 uint32_t _cnt; \
986 char **_vals = NULL; \
987 attr = NULL; \
988 _status = find_drsuapi_attr_string(mem_ctx, cur, \
989 DRSUAPI_ATTID_ ## attr, \
990 &_cnt, &_vals); \
991 if (NT_STATUS_EQUAL(_status, NT_STATUS_PROPSET_NOT_FOUND)) { \
992 if (!needed) { \
993 _status = NT_STATUS_OK; \
994 _cnt = 0; \
997 if (!NT_STATUS_IS_OK(_status)) { \
998 DEBUG(0,(__location__ "attr[%s] %s\n", \
999 #attr, nt_errstr(_status))); \
1000 return _status; \
1002 if (_cnt == 0) { \
1003 if (needed) { \
1004 talloc_free(_vals); \
1005 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1006 return NT_STATUS_OBJECT_NAME_NOT_FOUND; \
1008 } else if (_cnt > 1) { \
1009 talloc_free(_vals); \
1010 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1011 return NT_STATUS_INTERNAL_DB_CORRUPTION; \
1012 } else { \
1013 attr = talloc_move(mem_ctx, &_vals[0]); \
1015 talloc_free(_vals); \
1016 } while(0)
1018 #define GET_UINT32_EX(attr, needed) do { \
1019 NTSTATUS _status; \
1020 uint32_t _cnt; \
1021 int32_t*_vals = NULL; \
1022 attr = 0; \
1023 _status = find_drsuapi_attr_int32(mem_ctx, cur, \
1024 DRSUAPI_ATTID_ ## attr, \
1025 &_cnt, &_vals); \
1026 if (NT_STATUS_EQUAL(_status, NT_STATUS_PROPSET_NOT_FOUND)) { \
1027 if (!needed) { \
1028 _status = NT_STATUS_OK; \
1029 _cnt = 0; \
1032 if (!NT_STATUS_IS_OK(_status)) { \
1033 DEBUG(0,(__location__ "attr[%s] %s\n", \
1034 #attr, nt_errstr(_status))); \
1035 return _status; \
1037 if (_cnt == 0) { \
1038 if (needed) { \
1039 talloc_free(_vals); \
1040 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1041 return NT_STATUS_OBJECT_NAME_NOT_FOUND; \
1043 } else if (_cnt > 1) { \
1044 talloc_free(_vals); \
1045 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1046 return NT_STATUS_INTERNAL_DB_CORRUPTION; \
1047 } else { \
1048 attr = (uint32_t)_vals[0]; \
1050 talloc_free(_vals); \
1051 } while(0)
1053 #define GET_UINT64_EX(attr, needed) do { \
1054 NTSTATUS _status; \
1055 uint32_t _cnt; \
1056 int64_t *_vals = NULL; \
1057 attr = 0; \
1058 _status = find_drsuapi_attr_int64(mem_ctx, cur, \
1059 DRSUAPI_ATTID_ ## attr, \
1060 &_cnt, &_vals); \
1061 if (NT_STATUS_EQUAL(_status, NT_STATUS_PROPSET_NOT_FOUND)) { \
1062 if (!needed) { \
1063 _status = NT_STATUS_OK; \
1064 _cnt = 0; \
1067 if (!NT_STATUS_IS_OK(_status)) { \
1068 DEBUG(0,(__location__ "attr[%s] %s\n", \
1069 #attr, nt_errstr(_status))); \
1070 return _status; \
1072 if (_cnt == 0) { \
1073 if (needed) { \
1074 talloc_free(_vals); \
1075 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1076 return NT_STATUS_OBJECT_NAME_NOT_FOUND; \
1078 } else if (_cnt > 1) { \
1079 talloc_free(_vals); \
1080 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1081 return NT_STATUS_INTERNAL_DB_CORRUPTION; \
1082 } else { \
1083 attr = (uint64_t)_vals[0]; \
1085 talloc_free(_vals); \
1086 } while(0)
1088 #define GET_BLOB(attr) GET_BLOB_EX(attr, false)
1089 #define GET_STRING(attr) GET_STRING_EX(attr, false)
1090 #define GET_UINT32(attr) GET_UINT32_EX(attr, false)
1091 #define GET_UINT64(attr) GET_UINT64_EX(attr, false)
1093 /* Convert a struct samu_DELTA to a struct samu. */
1094 #define STRING_CHANGED (old_string && !new_string) ||\
1095 (!old_string && new_string) ||\
1096 (old_string && new_string && (strcmp(old_string, new_string) != 0))
1098 #define STRING_CHANGED_NC(s1,s2) ((s1) && !(s2)) ||\
1099 (!(s1) && (s2)) ||\
1100 ((s1) && (s2) && (strcmp((s1), (s2)) != 0))
1102 /****************************************************************
1103 ****************************************************************/
1105 static NTSTATUS sam_account_from_object(struct samu *account,
1106 struct drsuapi_DsReplicaObjectListItemEx *cur)
1108 TALLOC_CTX *mem_ctx = account;
1109 const char *old_string, *new_string;
1110 struct dom_sid_buf buf;
1111 time_t unix_time, stored_time;
1112 NTSTATUS status;
1114 NTTIME lastLogon;
1115 NTTIME lastLogoff;
1116 NTTIME pwdLastSet;
1117 NTTIME accountExpires;
1118 const char *sAMAccountName;
1119 const char *displayName;
1120 const char *homeDirectory;
1121 const char *homeDrive;
1122 const char *scriptPath;
1123 const char *profilePath;
1124 const char *description;
1125 const char *userWorkstations;
1126 DATA_BLOB userParameters;
1127 struct dom_sid objectSid;
1128 uint32_t primaryGroupID;
1129 uint32_t userAccountControl;
1130 DATA_BLOB logonHours;
1131 uint32_t badPwdCount;
1132 uint32_t logonCount;
1133 DATA_BLOB unicodePwd;
1134 DATA_BLOB dBCSPwd;
1136 uint32_t rid = 0;
1137 uint32_t acct_flags;
1138 uint32_t units_per_week;
1140 objectSid = cur->object.identifier->sid;
1141 GET_STRING_EX(sAMAccountName, true);
1142 DEBUG(0,("sam_account_from_object(%s, %s) start\n",
1143 sAMAccountName,
1144 dom_sid_str_buf(&objectSid, &buf)));
1145 GET_UINT64(lastLogon);
1146 GET_UINT64(lastLogoff);
1147 GET_UINT64(pwdLastSet);
1148 GET_UINT64(accountExpires);
1149 GET_STRING(displayName);
1150 GET_STRING(homeDirectory);
1151 GET_STRING(homeDrive);
1152 GET_STRING(scriptPath);
1153 GET_STRING(profilePath);
1154 GET_STRING(description);
1155 GET_STRING(userWorkstations);
1156 GET_BLOB(userParameters);
1157 GET_UINT32(primaryGroupID);
1158 GET_UINT32(userAccountControl);
1159 GET_BLOB(logonHours);
1160 GET_UINT32(badPwdCount);
1161 GET_UINT32(logonCount);
1162 GET_BLOB(unicodePwd);
1163 GET_BLOB(dBCSPwd);
1165 status = dom_sid_split_rid(mem_ctx, &objectSid, NULL, &rid);
1166 if (!NT_STATUS_IS_OK(status)) {
1167 return status;
1169 acct_flags = ds_uf2acb(userAccountControl);
1171 /* Username, fullname, home dir, dir drive, logon script, acct
1172 desc, workstations, profile. */
1174 if (sAMAccountName) {
1175 old_string = pdb_get_nt_username(account);
1176 new_string = sAMAccountName;
1178 if (STRING_CHANGED) {
1179 pdb_set_nt_username(account, new_string, PDB_CHANGED);
1182 /* Unix username is the same - for sanity */
1183 old_string = pdb_get_username( account );
1184 if (STRING_CHANGED) {
1185 pdb_set_username(account, new_string, PDB_CHANGED);
1189 if (displayName) {
1190 old_string = pdb_get_fullname(account);
1191 new_string = displayName;
1193 if (STRING_CHANGED)
1194 pdb_set_fullname(account, new_string, PDB_CHANGED);
1197 if (homeDirectory) {
1198 old_string = pdb_get_homedir(account);
1199 new_string = homeDirectory;
1201 if (STRING_CHANGED)
1202 pdb_set_homedir(account, new_string, PDB_CHANGED);
1205 if (homeDrive) {
1206 old_string = pdb_get_dir_drive(account);
1207 new_string = homeDrive;
1209 if (STRING_CHANGED)
1210 pdb_set_dir_drive(account, new_string, PDB_CHANGED);
1213 if (scriptPath) {
1214 old_string = pdb_get_logon_script(account);
1215 new_string = scriptPath;
1217 if (STRING_CHANGED)
1218 pdb_set_logon_script(account, new_string, PDB_CHANGED);
1221 if (description) {
1222 old_string = pdb_get_acct_desc(account);
1223 new_string = description;
1225 if (STRING_CHANGED)
1226 pdb_set_acct_desc(account, new_string, PDB_CHANGED);
1229 if (userWorkstations) {
1230 old_string = pdb_get_workstations(account);
1231 new_string = userWorkstations;
1233 if (STRING_CHANGED)
1234 pdb_set_workstations(account, new_string, PDB_CHANGED);
1237 if (profilePath) {
1238 old_string = pdb_get_profile_path(account);
1239 new_string = profilePath;
1241 if (STRING_CHANGED)
1242 pdb_set_profile_path(account, new_string, PDB_CHANGED);
1245 if (userParameters.data) {
1246 char *newstr = NULL;
1247 old_string = pdb_get_munged_dial(account);
1249 if (userParameters.length != 0) {
1250 newstr = base64_encode_data_blob(talloc_tos(),
1251 userParameters);
1252 SMB_ASSERT(newstr != NULL);
1255 if (STRING_CHANGED_NC(old_string, newstr))
1256 pdb_set_munged_dial(account, newstr, PDB_CHANGED);
1257 TALLOC_FREE(newstr);
1260 /* User and group sid */
1261 if (rid != 0 && pdb_get_user_rid(account) != rid) {
1262 pdb_set_user_sid_from_rid(account, rid, PDB_CHANGED);
1264 if (primaryGroupID != 0 && pdb_get_group_rid(account) != primaryGroupID) {
1265 pdb_set_group_sid_from_rid(account, primaryGroupID, PDB_CHANGED);
1268 /* Logon and password information */
1269 if (!nt_time_is_zero(&lastLogon)) {
1270 unix_time = nt_time_to_unix(lastLogon);
1271 stored_time = pdb_get_logon_time(account);
1272 if (stored_time != unix_time)
1273 pdb_set_logon_time(account, unix_time, PDB_CHANGED);
1276 if (!nt_time_is_zero(&lastLogoff)) {
1277 unix_time = nt_time_to_unix(lastLogoff);
1278 stored_time = pdb_get_logoff_time(account);
1279 if (stored_time != unix_time)
1280 pdb_set_logoff_time(account, unix_time,PDB_CHANGED);
1283 /* Logon Divs */
1284 units_per_week = logonHours.length * 8;
1286 if (pdb_get_logon_divs(account) != units_per_week) {
1287 pdb_set_logon_divs(account, units_per_week, PDB_CHANGED);
1290 /* Logon Hours Len */
1291 if (units_per_week/8 != pdb_get_hours_len(account)) {
1292 pdb_set_hours_len(account, units_per_week/8, PDB_CHANGED);
1295 /* Logon Hours */
1296 if (logonHours.data) {
1297 char oldstr[44], newstr[44];
1298 pdb_sethexhours(oldstr, pdb_get_hours(account));
1299 pdb_sethexhours(newstr, logonHours.data);
1300 if (!strequal(oldstr, newstr)) {
1301 pdb_set_hours(account, logonHours.data,
1302 logonHours.length, PDB_CHANGED);
1306 if (pdb_get_bad_password_count(account) != badPwdCount)
1307 pdb_set_bad_password_count(account, badPwdCount, PDB_CHANGED);
1309 if (pdb_get_logon_count(account) != logonCount)
1310 pdb_set_logon_count(account, logonCount, PDB_CHANGED);
1312 if (!nt_time_is_zero(&pwdLastSet)) {
1313 unix_time = nt_time_to_unix(pwdLastSet);
1314 stored_time = pdb_get_pass_last_set_time(account);
1315 if (stored_time != unix_time)
1316 pdb_set_pass_last_set_time(account, unix_time, PDB_CHANGED);
1317 } else {
1318 /* no last set time, make it now */
1319 pdb_set_pass_last_set_time(account, time(NULL), PDB_CHANGED);
1322 if (!nt_time_is_zero(&accountExpires)) {
1323 unix_time = nt_time_to_unix(accountExpires);
1324 stored_time = pdb_get_kickoff_time(account);
1325 if (stored_time != unix_time)
1326 pdb_set_kickoff_time(account, unix_time, PDB_CHANGED);
1329 /* Decode hashes from password hash
1330 Note that win2000 may send us all zeros for the hashes if it doesn't
1331 think this channel is secure enough - don't set the passwords at all
1332 in that case
1334 if (dBCSPwd.length == 16 && !all_zero(dBCSPwd.data, 16)) {
1335 pdb_set_lanman_passwd(account, dBCSPwd.data, PDB_CHANGED);
1338 if (unicodePwd.length == 16 && !all_zero(unicodePwd.data, 16)) {
1339 pdb_set_nt_passwd(account, unicodePwd.data, PDB_CHANGED);
1342 /* TODO: history */
1344 /* TODO: account expiry time */
1346 pdb_set_acct_ctrl(account, acct_flags, PDB_CHANGED);
1348 pdb_set_domain(account, lp_workgroup(), PDB_CHANGED);
1350 DEBUG(0,("sam_account_from_object(%s, %s) done\n",
1351 sAMAccountName,
1352 dom_sid_str_buf(&objectSid, &buf)));
1353 return NT_STATUS_OK;
1356 /****************************************************************
1357 ****************************************************************/
1359 static NTSTATUS handle_account_object(struct dssync_passdb *pctx,
1360 TALLOC_CTX *mem_ctx,
1361 struct dssync_passdb_obj *obj)
1363 struct drsuapi_DsReplicaObjectListItemEx *cur = obj->cur;
1364 NTSTATUS status;
1365 fstring account;
1366 struct samu *sam_account=NULL;
1367 GROUP_MAP *map;
1368 struct group *grp;
1369 struct dom_sid user_sid;
1370 struct dom_sid group_sid;
1371 struct dom_sid_buf buf;
1372 struct passwd *passwd = NULL;
1373 uint32_t acct_flags;
1374 uint32_t rid;
1376 const char *sAMAccountName;
1377 uint32_t userAccountControl;
1379 user_sid = cur->object.identifier->sid;
1380 GET_STRING_EX(sAMAccountName, true);
1381 GET_UINT32_EX(userAccountControl, true);
1383 status = dom_sid_split_rid(mem_ctx, &user_sid, NULL, &rid);
1384 if (!NT_STATUS_IS_OK(status)) {
1385 return status;
1388 fstrcpy(account, sAMAccountName);
1389 if (rid == DOMAIN_RID_GUEST) {
1391 * pdb_getsampwsid() has special handling for DOMAIN_RID_GUEST
1392 * that's why we need to ignore it here.
1394 * pdb_smbpasswd.c also has some DOMAIN_RID_GUEST related
1395 * code...
1397 DEBUG(0,("Ignore %s - %s\n",
1398 account,
1399 dom_sid_str_buf(&user_sid, &buf)));
1400 return NT_STATUS_OK;
1402 DEBUG(0,("Creating account: %s\n", account));
1404 if ( !(sam_account = samu_new(mem_ctx)) ) {
1405 return NT_STATUS_NO_MEMORY;
1408 acct_flags = ds_uf2acb(userAccountControl);
1409 status = smb_create_user(sam_account, acct_flags, account, &passwd);
1410 if (!NT_STATUS_IS_OK(status)) {
1411 DEBUG(0,("Could not create posix account info for '%s'- %s\n",
1412 account, nt_errstr(status)));
1413 TALLOC_FREE(sam_account);
1414 return status;
1417 DEBUG(3, ("Attempting to find SID %s for user %s in the passdb\n",
1418 dom_sid_str_buf(&user_sid, &buf),
1419 account));
1420 if (!pdb_getsampwsid(sam_account, &user_sid)) {
1421 sam_account_from_object(sam_account, cur);
1422 DEBUG(3, ("Attempting to add user SID %s for user %s in the passdb\n",
1423 dom_sid_str_buf(&user_sid, &buf),
1424 pdb_get_username(sam_account)));
1425 if (!NT_STATUS_IS_OK(pdb_add_sam_account(sam_account))) {
1426 DEBUG(1, ("SAM Account for %s failed to be added to the passdb!\n",
1427 account));
1428 TALLOC_FREE(sam_account);
1429 return NT_STATUS_ACCESS_DENIED;
1431 } else {
1432 sam_account_from_object(sam_account, cur);
1433 DEBUG(3, ("Attempting to update user SID %s for user %s in the passdb\n",
1434 dom_sid_str_buf(&user_sid, &buf),
1435 pdb_get_username(sam_account)));
1436 if (!NT_STATUS_IS_OK(pdb_update_sam_account(sam_account))) {
1437 DEBUG(1, ("SAM Account for %s failed to be updated in the passdb!\n",
1438 account));
1439 TALLOC_FREE(sam_account);
1440 return NT_STATUS_ACCESS_DENIED;
1444 if (pdb_get_group_sid(sam_account) == NULL) {
1445 TALLOC_FREE(sam_account);
1446 return NT_STATUS_UNSUCCESSFUL;
1449 group_sid = *pdb_get_group_sid(sam_account);
1451 map = talloc_zero(NULL, GROUP_MAP);
1452 if (!map) {
1453 return NT_STATUS_NO_MEMORY;
1456 if (!pdb_getgrsid(map, group_sid)) {
1457 DEBUG(0, ("Primary group of %s has no mapping!\n",
1458 pdb_get_username(sam_account)));
1459 } else {
1460 if (map->gid != passwd->pw_gid) {
1461 if (!(grp = getgrgid(map->gid))) {
1462 DEBUG(0, ("Could not find unix group %lu for user %s (group SID=%s)\n",
1463 (unsigned long)map->gid, pdb_get_username(sam_account),
1464 dom_sid_str_buf(&group_sid, &buf)));
1465 } else {
1466 smb_set_primary_group(grp->gr_name, pdb_get_username(sam_account));
1471 TALLOC_FREE(map);
1473 if ( !passwd ) {
1474 DEBUG(1, ("No unix user for this account (%s), cannot adjust mappings\n",
1475 pdb_get_username(sam_account)));
1478 TALLOC_FREE(sam_account);
1479 return NT_STATUS_OK;
1482 /****************************************************************
1483 ****************************************************************/
1485 static NTSTATUS handle_alias_object(struct dssync_passdb *pctx,
1486 TALLOC_CTX *mem_ctx,
1487 struct dssync_passdb_obj *obj)
1489 struct drsuapi_DsReplicaObjectListItemEx *cur = obj->cur;
1490 NTSTATUS status;
1491 struct group *grp = NULL;
1492 struct dom_sid group_sid;
1493 uint32_t rid = 0;
1494 struct dom_sid *dom_sid = NULL;
1495 struct dom_sid_buf sid_str;
1496 GROUP_MAP *map;
1497 bool insert = true;
1499 const char *sAMAccountName;
1500 const char *description;
1501 uint32_t i;
1502 uint32_t num_members = 0;
1503 struct drsuapi_DsReplicaObjectIdentifier3 *members = NULL;
1505 group_sid = cur->object.identifier->sid;
1506 GET_STRING_EX(sAMAccountName, true);
1507 GET_STRING(description);
1509 status = find_drsuapi_attr_dn(obj, cur, DRSUAPI_ATTID_member,
1510 &num_members, &members);
1511 if (NT_STATUS_EQUAL(status, NT_STATUS_PROPSET_NOT_FOUND)) {
1512 status = NT_STATUS_OK;
1514 if (!NT_STATUS_IS_OK(status)) {
1515 return status;
1518 dom_sid_split_rid(mem_ctx, &group_sid, &dom_sid, &rid);
1520 map = talloc_zero(mem_ctx, GROUP_MAP);
1521 if (map == NULL) {
1522 status = NT_STATUS_NO_MEMORY;
1523 goto done;
1526 map->nt_name = talloc_strdup(map, sAMAccountName);
1527 if (map->nt_name == NULL) {
1528 status = NT_STATUS_NO_MEMORY;
1529 goto done;
1532 if (description) {
1533 map->comment = talloc_strdup(map, description);
1534 } else {
1535 map->comment = talloc_strdup(map, "");
1537 if (map->comment == NULL) {
1538 status = NT_STATUS_NO_MEMORY;
1539 goto done;
1542 DEBUG(0,("Creating alias[%s] - %s members[%u]\n",
1543 map->nt_name,
1544 dom_sid_str_buf(&group_sid, &sid_str),
1545 num_members));
1547 status = dssync_insert_obj(pctx, pctx->aliases, obj);
1548 if (!NT_STATUS_IS_OK(status)) {
1549 goto done;
1552 if (pdb_getgrsid(map, group_sid)) {
1553 if (map->gid != -1) {
1554 grp = getgrgid(map->gid);
1556 insert = false;
1559 if (grp == NULL) {
1560 gid_t gid;
1562 /* No group found from mapping, find it from its name. */
1563 if ((grp = getgrnam(map->nt_name)) == NULL) {
1565 /* No appropriate group found, create one */
1567 DEBUG(0, ("Creating unix group: '%s'\n",
1568 map->nt_name));
1570 if (smb_create_group(map->nt_name, &gid) != 0) {
1571 status = NT_STATUS_ACCESS_DENIED;
1572 goto done;
1575 if ((grp = getgrgid(gid)) == NULL) {
1576 status = NT_STATUS_ACCESS_DENIED;
1577 goto done;
1582 map->gid = grp->gr_gid;
1583 map->sid = group_sid;
1585 if (dom_sid_equal(dom_sid, &global_sid_Builtin)) {
1587 * pdb_ldap does not like SID_NAME_WKN_GRP...
1589 * map.sid_name_use = SID_NAME_WKN_GRP;
1591 map->sid_name_use = SID_NAME_ALIAS;
1592 } else {
1593 map->sid_name_use = SID_NAME_ALIAS;
1596 if (insert) {
1597 pdb_add_group_mapping_entry(map);
1598 } else {
1599 pdb_update_group_mapping_entry(map);
1602 for (i=0; i < num_members; i++) {
1603 struct dssync_passdb_mem *mem;
1605 status = dssync_create_mem(pctx, obj,
1606 true /* active */,
1607 &members[i], &mem);
1608 if (!NT_STATUS_IS_OK(status)) {
1609 goto done;
1613 status = NT_STATUS_OK;
1615 done:
1616 TALLOC_FREE(map);
1617 return status;
1620 /****************************************************************
1621 ****************************************************************/
1623 static NTSTATUS handle_group_object(struct dssync_passdb *pctx,
1624 TALLOC_CTX *mem_ctx,
1625 struct dssync_passdb_obj *obj)
1627 struct drsuapi_DsReplicaObjectListItemEx *cur = obj->cur;
1628 NTSTATUS status;
1629 struct group *grp = NULL;
1630 struct dom_sid group_sid;
1631 struct dom_sid_buf sid_str;
1632 GROUP_MAP *map;
1633 bool insert = true;
1635 const char *sAMAccountName;
1636 const char *description;
1637 uint32_t i;
1638 uint32_t num_members = 0;
1639 struct drsuapi_DsReplicaObjectIdentifier3 *members = NULL;
1641 group_sid = cur->object.identifier->sid;
1642 GET_STRING_EX(sAMAccountName, true);
1643 GET_STRING(description);
1645 status = find_drsuapi_attr_dn(obj, cur, DRSUAPI_ATTID_member,
1646 &num_members, &members);
1647 if (NT_STATUS_EQUAL(status, NT_STATUS_PROPSET_NOT_FOUND)) {
1648 status = NT_STATUS_OK;
1650 if (!NT_STATUS_IS_OK(status)) {
1651 return status;
1654 map = talloc_zero(NULL, GROUP_MAP);
1655 if (!map) {
1656 return NT_STATUS_NO_MEMORY;
1659 map->nt_name = talloc_strdup(map, sAMAccountName);
1660 if (!map->nt_name) {
1661 status = NT_STATUS_NO_MEMORY;
1662 goto done;
1664 if (description) {
1665 map->comment = talloc_strdup(map, description);
1666 } else {
1667 map->comment = talloc_strdup(map, "");
1669 if (!map->comment) {
1670 status = NT_STATUS_NO_MEMORY;
1671 goto done;
1674 DEBUG(0,("Creating group[%s] - %s members [%u]\n",
1675 map->nt_name,
1676 dom_sid_str_buf(&group_sid, &sid_str),
1677 num_members));
1679 status = dssync_insert_obj(pctx, pctx->groups, obj);
1680 if (!NT_STATUS_IS_OK(status)) {
1681 goto done;
1684 if (pdb_getgrsid(map, group_sid)) {
1685 if (map->gid != -1) {
1686 grp = getgrgid(map->gid);
1688 insert = false;
1691 if (grp == NULL) {
1692 gid_t gid;
1694 /* No group found from mapping, find it from its name. */
1695 if ((grp = getgrnam(map->nt_name)) == NULL) {
1697 /* No appropriate group found, create one */
1699 DEBUG(0, ("Creating unix group: '%s'\n",
1700 map->nt_name));
1702 if (smb_create_group(map->nt_name, &gid) != 0) {
1703 status = NT_STATUS_ACCESS_DENIED;
1704 goto done;
1707 if ((grp = getgrnam(map->nt_name)) == NULL) {
1708 status = NT_STATUS_ACCESS_DENIED;
1709 goto done;
1714 map->gid = grp->gr_gid;
1715 map->sid = group_sid;
1716 map->sid_name_use = SID_NAME_DOM_GRP;
1718 if (insert) {
1719 pdb_add_group_mapping_entry(map);
1720 } else {
1721 pdb_update_group_mapping_entry(map);
1724 for (i=0; i < num_members; i++) {
1725 struct dssync_passdb_mem *mem;
1727 status = dssync_create_mem(pctx, obj,
1728 true /* active */,
1729 &members[i], &mem);
1730 if (!NT_STATUS_IS_OK(status)) {
1731 goto done;
1735 status = NT_STATUS_OK;
1737 done:
1738 TALLOC_FREE(map);
1739 return status;
1742 /****************************************************************
1743 ****************************************************************/
1745 static NTSTATUS handle_interdomain_trust_object(struct dssync_passdb *pctx,
1746 TALLOC_CTX *mem_ctx,
1747 struct dssync_passdb_obj *obj)
1749 struct drsuapi_DsReplicaObjectListItemEx *cur = obj->cur;
1750 DEBUG(0,("trust: %s\n", cur->object.identifier->dn));
1751 return NT_STATUS_NOT_IMPLEMENTED;
1754 /****************************************************************
1755 ****************************************************************/
1757 struct dssync_object_table_t {
1758 uint32_t type;
1759 NTSTATUS (*fn) (struct dssync_passdb *pctx,
1760 TALLOC_CTX *mem_ctx,
1761 struct dssync_passdb_obj *obj);
1764 static const struct dssync_object_table_t dssync_object_table[] = {
1765 { ATYPE_NORMAL_ACCOUNT, handle_account_object },
1766 { ATYPE_WORKSTATION_TRUST, handle_account_object },
1767 { ATYPE_SECURITY_LOCAL_GROUP, handle_alias_object },
1768 { ATYPE_SECURITY_GLOBAL_GROUP, handle_group_object },
1769 { ATYPE_INTERDOMAIN_TRUST, handle_interdomain_trust_object },
1772 /****************************************************************
1773 ****************************************************************/
1775 static NTSTATUS parse_object(struct dssync_passdb *pctx,
1776 TALLOC_CTX *mem_ctx,
1777 struct drsuapi_DsReplicaObjectListItemEx *cur)
1779 NTSTATUS status = NT_STATUS_OK;
1780 DATA_BLOB *blob;
1781 int i = 0;
1782 int a = 0;
1783 struct drsuapi_DsReplicaAttribute *attr;
1785 char *name = NULL;
1786 uint32_t sam_type = 0;
1788 DEBUG(3, ("parsing object '%s'\n", cur->object.identifier->dn));
1790 for (i=0; i < cur->object.attribute_ctr.num_attributes; i++) {
1792 attr = &cur->object.attribute_ctr.attributes[i];
1794 if (attr->value_ctr.num_values != 1) {
1795 continue;
1798 if (!attr->value_ctr.values[0].blob) {
1799 continue;
1802 blob = attr->value_ctr.values[0].blob;
1804 switch (attr->attid) {
1805 case DRSUAPI_ATTID_sAMAccountName:
1806 pull_string_talloc(mem_ctx, NULL, 0, &name,
1807 blob->data, blob->length,
1808 STR_UNICODE);
1809 break;
1810 case DRSUAPI_ATTID_sAMAccountType:
1811 sam_type = IVAL(blob->data, 0);
1812 break;
1813 default:
1814 break;
1818 for (a=0; a < ARRAY_SIZE(dssync_object_table); a++) {
1819 if (sam_type == dssync_object_table[a].type) {
1820 if (dssync_object_table[a].fn) {
1821 struct dssync_passdb_obj *obj = NULL;
1822 status = dssync_create_obj(pctx, pctx->all,
1823 sam_type, cur, &obj);
1824 if (!NT_STATUS_IS_OK(status)) {
1825 break;
1827 status = dssync_object_table[a].fn(pctx,
1828 mem_ctx,
1829 obj);
1830 break;
1835 return status;
1838 static NTSTATUS parse_link(struct dssync_passdb *pctx,
1839 TALLOC_CTX *mem_ctx,
1840 struct drsuapi_DsReplicaLinkedAttribute *cur)
1842 struct drsuapi_DsReplicaObjectIdentifier3 *id3;
1843 const DATA_BLOB *blob;
1844 enum ndr_err_code ndr_err;
1845 NTSTATUS status;
1846 bool active = false;
1847 struct dssync_passdb_mem *mem;
1848 struct dssync_passdb_obj *obj;
1850 if (cur->attid != DRSUAPI_ATTID_member) {
1851 return NT_STATUS_OK;
1854 if (cur->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE) {
1855 active = true;
1858 DEBUG(3, ("parsing link '%s' - %s\n",
1859 cur->identifier->dn, active?"adding":"deleting"));
1861 blob = cur->value.blob;
1863 if (blob == NULL) {
1864 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1867 obj = dssync_search_obj_by_guid(pctx, pctx->all, &cur->identifier->guid);
1868 if (obj == NULL) {
1869 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1872 id3 = talloc_zero(obj, struct drsuapi_DsReplicaObjectIdentifier3);
1873 if (id3 == NULL) {
1874 return NT_STATUS_NO_MEMORY;
1877 /* windows sometimes sends an extra two pad bytes here */
1878 ndr_err = ndr_pull_struct_blob(blob, id3, id3,
1879 (ndr_pull_flags_fn_t)ndr_pull_drsuapi_DsReplicaObjectIdentifier3);
1880 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1881 status = ndr_map_error2ntstatus(ndr_err);
1882 return status;
1885 status = dssync_create_mem(pctx, obj,
1886 active,
1887 id3, &mem);
1888 if (!NT_STATUS_IS_OK(status)) {
1889 return status;
1892 return NT_STATUS_OK;
1895 /****************************************************************
1896 ****************************************************************/
1898 static NTSTATUS passdb_process_objects(struct dssync_context *ctx,
1899 TALLOC_CTX *mem_ctx,
1900 struct drsuapi_DsReplicaObjectListItemEx *cur,
1901 struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr)
1903 NTSTATUS status = NT_STATUS_OK;
1904 struct dssync_passdb *pctx =
1905 talloc_get_type_abort(ctx->private_data,
1906 struct dssync_passdb);
1908 for (; cur; cur = cur->next_object) {
1909 status = parse_object(pctx, mem_ctx, cur);
1910 if (!NT_STATUS_IS_OK(status)) {
1911 goto out;
1915 out:
1916 return status;
1919 /****************************************************************
1920 ****************************************************************/
1922 static NTSTATUS passdb_process_links(struct dssync_context *ctx,
1923 TALLOC_CTX *mem_ctx,
1924 uint32_t count,
1925 struct drsuapi_DsReplicaLinkedAttribute *links,
1926 struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr)
1928 NTSTATUS status = NT_STATUS_OK;
1929 struct dssync_passdb *pctx =
1930 talloc_get_type_abort(ctx->private_data,
1931 struct dssync_passdb);
1932 uint32_t i;
1934 for (i = 0; i < count; i++) {
1935 status = parse_link(pctx, mem_ctx, &links[i]);
1936 if (!NT_STATUS_IS_OK(status)) {
1937 goto out;
1941 out:
1942 return status;
1945 /****************************************************************
1946 ****************************************************************/
1948 const struct dssync_ops libnet_dssync_passdb_ops = {
1949 .startup = passdb_startup,
1950 .process_objects = passdb_process_objects,
1951 .process_links = passdb_process_links,
1952 .finish = passdb_finish,