s3:waf: Fix code spelling
[Samba.git] / source3 / libnet / libnet_dssync_passdb.c
blob7d5ef64e8f414f867837fa136690fd440ce3ac25
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"
32 #include "lib/util/string_wrappers.h"
34 /****************************************************************
35 ****************************************************************/
37 struct dssync_passdb {
38 struct pdb_methods *methods;
39 struct db_context *all;
40 struct db_context *aliases;
41 struct db_context *groups;
44 struct dssync_passdb_obj {
45 struct dssync_passdb_obj *self;
46 uint32_t type;
47 struct drsuapi_DsReplicaObjectListItemEx *cur;
48 TDB_DATA key;
49 TDB_DATA data;
50 struct db_context *members;
53 struct dssync_passdb_mem {
54 struct dssync_passdb_mem *self;
55 bool active;
56 struct drsuapi_DsReplicaObjectIdentifier3 *cur;
57 struct dssync_passdb_obj *obj;
58 TDB_DATA key;
59 TDB_DATA data;
62 static NTSTATUS dssync_insert_obj(struct dssync_passdb *pctx,
63 struct db_context *db,
64 struct dssync_passdb_obj *obj)
66 NTSTATUS status;
67 struct db_record *rec;
68 TDB_DATA value;
70 rec = dbwrap_fetch_locked(db, talloc_tos(), obj->key);
71 if (rec == NULL) {
72 return NT_STATUS_NO_MEMORY;
75 value = dbwrap_record_get_value(rec);
76 if (value.dsize != 0) {
77 abort();
80 status = dbwrap_record_store(rec, obj->data, TDB_INSERT);
81 if (!NT_STATUS_IS_OK(status)) {
82 TALLOC_FREE(rec);
83 return status;
85 TALLOC_FREE(rec);
86 return NT_STATUS_OK;
89 static struct dssync_passdb_obj *dssync_parse_obj(const TDB_DATA data)
91 struct dssync_passdb_obj *obj;
93 if (data.dsize != sizeof(obj)) {
94 return NULL;
98 * we need to copy the pointer to avoid alignment problems
99 * on some systems.
101 memcpy(&obj, data.dptr, sizeof(obj));
103 return talloc_get_type_abort(obj, struct dssync_passdb_obj);
106 static struct dssync_passdb_obj *dssync_search_obj_by_guid(struct dssync_passdb *pctx,
107 struct db_context *db,
108 const struct GUID *guid)
110 struct dssync_passdb_obj *obj;
111 TDB_DATA key;
112 TDB_DATA data;
113 NTSTATUS status;
115 key = make_tdb_data((const uint8_t *)(const void *)guid,
116 sizeof(*guid));
118 status = dbwrap_fetch(db, talloc_tos(), key, &data);
119 if (!NT_STATUS_IS_OK(status)) {
120 return NULL;
123 obj = dssync_parse_obj(data);
124 return obj;
127 static NTSTATUS dssync_create_obj(struct dssync_passdb *pctx,
128 struct db_context *db,
129 uint32_t type,
130 struct drsuapi_DsReplicaObjectListItemEx *cur,
131 struct dssync_passdb_obj **_obj)
133 NTSTATUS status;
134 struct dssync_passdb_obj *obj;
136 obj = talloc_zero(pctx, struct dssync_passdb_obj);
137 if (obj == NULL) {
138 return NT_STATUS_NO_MEMORY;
140 obj->self = obj;
141 obj->cur = cur;
142 obj->type = type;
143 obj->key = make_tdb_data((const uint8_t *)(void *)&cur->object.identifier->guid,
144 sizeof(cur->object.identifier->guid));
145 obj->data = make_tdb_data((const uint8_t *)(void *)&obj->self,
146 sizeof(obj->self));
148 obj->members = db_open_rbt(obj);
149 if (obj->members == NULL) {
150 return NT_STATUS_NO_MEMORY;
153 status = dssync_insert_obj(pctx, db, obj);
154 if (!NT_STATUS_IS_OK(status)) {
155 TALLOC_FREE(obj);
156 return status;
158 *_obj = obj;
159 return NT_STATUS_OK;
162 static NTSTATUS dssync_insert_mem(struct dssync_passdb *pctx,
163 struct dssync_passdb_obj *obj,
164 struct dssync_passdb_mem *mem)
166 NTSTATUS status;
167 struct db_record *rec;
168 TDB_DATA value;
170 rec = dbwrap_fetch_locked(obj->members, talloc_tos(), mem->key);
171 if (rec == NULL) {
172 return NT_STATUS_NO_MEMORY;
175 value = dbwrap_record_get_value(rec);
176 if (value.dsize != 0) {
177 abort();
180 status = dbwrap_record_store(rec, mem->data, TDB_INSERT);
181 if (!NT_STATUS_IS_OK(status)) {
182 TALLOC_FREE(rec);
183 return status;
185 TALLOC_FREE(rec);
186 return NT_STATUS_OK;
189 static NTSTATUS dssync_create_mem(struct dssync_passdb *pctx,
190 struct dssync_passdb_obj *obj,
191 bool active,
192 struct drsuapi_DsReplicaObjectIdentifier3 *cur,
193 struct dssync_passdb_mem **_mem)
195 NTSTATUS status;
196 struct dssync_passdb_mem *mem;
198 mem = talloc_zero(pctx, struct dssync_passdb_mem);
199 if (mem == NULL) {
200 return NT_STATUS_NO_MEMORY;
202 mem->self = mem;
203 mem->cur = cur;
204 mem->active = active;
205 mem->obj = NULL;
206 mem->key = make_tdb_data((const uint8_t *)(void *)&cur->guid,
207 sizeof(cur->guid));
208 mem->data = make_tdb_data((const uint8_t *)(void *)&mem->self,
209 sizeof(mem->self));
211 status = dssync_insert_mem(pctx, obj, mem);
212 if (!NT_STATUS_IS_OK(status)) {
213 TALLOC_FREE(obj);
214 return status;
216 *_mem = mem;
217 return NT_STATUS_OK;
220 static struct dssync_passdb_mem *dssync_parse_mem(const TDB_DATA data)
222 struct dssync_passdb_mem *mem;
224 if (data.dsize != sizeof(mem)) {
225 return NULL;
229 * we need to copy the pointer to avoid alignment problems
230 * on some systems.
232 memcpy(&mem, data.dptr, sizeof(mem));
234 return talloc_get_type_abort(mem, struct dssync_passdb_mem);
237 static NTSTATUS passdb_startup(struct dssync_context *ctx, TALLOC_CTX *mem_ctx,
238 struct replUpToDateVectorBlob **pold_utdv)
240 NTSTATUS status;
241 struct dssync_passdb *pctx;
243 pctx = talloc_zero(mem_ctx, struct dssync_passdb);
244 if (pctx == NULL) {
245 return NT_STATUS_NO_MEMORY;
248 if (ctx->output_filename) {
249 status = make_pdb_method_name(&pctx->methods, ctx->output_filename);
250 } else {
251 status = make_pdb_method_name(&pctx->methods, lp_passdb_backend());
254 if (!NT_STATUS_IS_OK(status)) {
255 return status;
258 pctx->all = db_open_rbt(pctx);
259 if (pctx->all == NULL) {
260 return NT_STATUS_NO_MEMORY;
262 pctx->aliases = db_open_rbt(pctx);
263 if (pctx->aliases == NULL) {
264 return NT_STATUS_NO_MEMORY;
266 pctx->groups = db_open_rbt(pctx);
267 if (pctx->groups == NULL) {
268 return NT_STATUS_NO_MEMORY;
271 ctx->private_data = pctx;
273 return status;
276 /****************************************************************
277 ****************************************************************/
279 struct dssync_passdb_traverse_amembers {
280 struct dssync_context *ctx;
281 struct dssync_passdb_obj *obj;
282 const char *name;
283 uint32_t idx;
286 struct dssync_passdb_traverse_aliases {
287 struct dssync_context *ctx;
288 const char *name;
289 uint32_t idx;
292 static int dssync_passdb_traverse_amembers(struct db_record *rec,
293 void *private_data)
295 struct dssync_passdb_traverse_amembers *state =
296 (struct dssync_passdb_traverse_amembers *)private_data;
297 struct dssync_passdb *pctx =
298 talloc_get_type_abort(state->ctx->private_data,
299 struct dssync_passdb);
300 struct dssync_passdb_mem *mem;
301 NTSTATUS status;
302 struct dom_sid alias_sid;
303 struct dom_sid member_sid;
304 struct dom_sid_buf buf1, buf2;
305 const char *member_dn;
306 size_t num_members;
307 size_t i;
308 struct dom_sid *members;
309 bool is_member = false;
310 const char *action;
311 TDB_DATA value;
313 state->idx++;
315 alias_sid = state->obj->cur->object.identifier->sid;
317 value = dbwrap_record_get_value(rec);
318 mem = dssync_parse_mem(value);
319 if (mem == NULL) {
320 return -1;
323 member_sid = mem->cur->sid;
324 member_dn = mem->cur->dn;
326 mem->obj = dssync_search_obj_by_guid(pctx, pctx->all, &mem->cur->guid);
327 if (mem->obj == NULL) {
328 DEBUG(0,("alias[%s] member[%s] can't resolve member - ignoring\n",
329 dom_sid_str_buf(&alias_sid, &buf1),
330 is_null_sid(&member_sid)?
331 dom_sid_str_buf(&member_sid, &buf2):
332 member_dn));
333 return 0;
336 switch (mem->obj->type) {
337 case ATYPE_DISTRIBUTION_LOCAL_GROUP:
338 case ATYPE_DISTRIBUTION_GLOBAL_GROUP:
339 DEBUG(0, ("alias[%s] ignore distribution group [%s]\n",
340 dom_sid_str_buf(&alias_sid, &buf1),
341 member_dn));
342 return 0;
343 default:
344 break;
347 DEBUG(0,("alias[%s] member[%s]\n",
348 dom_sid_str_buf(&alias_sid, &buf1),
349 dom_sid_str_buf(&member_sid, &buf2)));
351 status = pdb_enum_aliasmem(&alias_sid, talloc_tos(),
352 &members, &num_members);
353 if (!NT_STATUS_IS_OK(status)) {
354 DEBUG(0, ("Could not find current alias members %s - %s\n",
355 dom_sid_str_buf(&alias_sid, &buf1),
356 nt_errstr(status)));
357 return -1;
360 for (i=0; i < num_members; i++) {
361 bool match;
363 match = dom_sid_equal(&members[i], &member_sid);
364 if (match) {
365 is_member = true;
366 break;
370 status = NT_STATUS_OK;
371 action = "none";
372 if (!is_member && mem->active) {
373 action = "add";
374 pdb_add_aliasmem(&alias_sid, &member_sid);
375 } else if (is_member && !mem->active) {
376 action = "delete";
377 pdb_del_aliasmem(&alias_sid, &member_sid);
379 if (!NT_STATUS_IS_OK(status)) {
380 DEBUG(0, ("Could not %s %s as alias members of %s - %s\n",
381 action,
382 dom_sid_str_buf(&member_sid, &buf1),
383 dom_sid_str_buf(&alias_sid, &buf2),
384 nt_errstr(status)));
385 return -1;
388 return 0;
391 static int dssync_passdb_traverse_aliases(struct db_record *rec,
392 void *private_data)
394 struct dssync_passdb_traverse_aliases *state =
395 (struct dssync_passdb_traverse_aliases *)private_data;
396 struct dssync_passdb *pctx =
397 talloc_get_type_abort(state->ctx->private_data,
398 struct dssync_passdb);
399 struct dssync_passdb_traverse_amembers mstate;
400 struct dssync_passdb_obj *obj;
401 TDB_DATA value;
402 NTSTATUS status;
404 state->idx++;
405 if (pctx->methods == NULL) {
406 return -1;
409 value = dbwrap_record_get_value(rec);
410 obj = dssync_parse_obj(value);
411 if (obj == NULL) {
412 return -1;
415 ZERO_STRUCT(mstate);
416 mstate.ctx = state->ctx;
417 mstate.name = "members";
418 mstate.obj = obj;
419 status = dbwrap_traverse_read(obj->members,
420 dssync_passdb_traverse_amembers,
421 &mstate, NULL);
422 if (!NT_STATUS_IS_OK(status)) {
423 return -1;
426 return 0;
429 struct dssync_passdb_traverse_gmembers {
430 struct dssync_context *ctx;
431 struct dssync_passdb_obj *obj;
432 const char *name;
433 uint32_t idx;
436 struct dssync_passdb_traverse_groups {
437 struct dssync_context *ctx;
438 const char *name;
439 uint32_t idx;
442 static int dssync_passdb_traverse_gmembers(struct db_record *rec,
443 void *private_data)
445 struct dssync_passdb_traverse_gmembers *state =
446 (struct dssync_passdb_traverse_gmembers *)private_data;
447 struct dssync_passdb *pctx =
448 talloc_get_type_abort(state->ctx->private_data,
449 struct dssync_passdb);
450 struct dssync_passdb_mem *mem;
451 NTSTATUS status;
452 char *nt_member = NULL;
453 char **unix_members;
454 struct dom_sid group_sid;
455 struct dom_sid member_sid;
456 struct dom_sid_buf buf1, buf2;
457 struct samu *member = NULL;
458 const char *member_dn = NULL;
459 GROUP_MAP *map;
460 struct group *grp;
461 uint32_t rid;
462 bool is_unix_member = false;
463 TDB_DATA value;
465 state->idx++;
467 group_sid = state->obj->cur->object.identifier->sid;
469 status = dom_sid_split_rid(talloc_tos(), &group_sid, NULL, &rid);
470 if (!NT_STATUS_IS_OK(status)) {
471 return -1;
474 value = dbwrap_record_get_value(rec);
476 mem = dssync_parse_mem(value);
477 if (mem == NULL) {
478 return -1;
481 member_sid = mem->cur->sid;
482 member_dn = mem->cur->dn;
484 mem->obj = dssync_search_obj_by_guid(pctx, pctx->all, &mem->cur->guid);
485 if (mem->obj == NULL) {
486 DEBUG(0,("group[%s] member[%s] can't resolve member - ignoring\n",
487 dom_sid_str_buf(&group_sid, &buf1),
488 is_null_sid(&member_sid)?
489 dom_sid_str_buf(&member_sid, &buf2):
490 member_dn));
491 return 0;
494 member_sid = mem->obj->cur->object.identifier->sid;
495 member_dn = mem->obj->cur->object.identifier->dn;
497 switch (mem->obj->type) {
498 case ATYPE_SECURITY_LOCAL_GROUP:
499 case ATYPE_SECURITY_GLOBAL_GROUP:
500 DEBUG(0, ("Group[%s] ignore member group [%s]\n",
501 dom_sid_str_buf(&group_sid, &buf1),
502 dom_sid_str_buf(&member_sid, &buf2)));
503 return 0;
505 case ATYPE_DISTRIBUTION_LOCAL_GROUP:
506 case ATYPE_DISTRIBUTION_GLOBAL_GROUP:
507 DEBUG(0, ("Group[%s] ignore distribution group [%s]\n",
508 dom_sid_str_buf(&group_sid, &buf1),
509 member_dn));
510 return 0;
511 default:
512 break;
515 map = talloc_zero(NULL, GROUP_MAP);
516 if (!map) {
517 return -1;
520 if (!get_domain_group_from_sid(group_sid, map)) {
521 DEBUG(0, ("Could not find global group %s\n",
522 dom_sid_str_buf(&group_sid, &buf1)));
523 //return NT_STATUS_NO_SUCH_GROUP;
524 TALLOC_FREE(map);
525 return -1;
528 if (!(grp = getgrgid(map->gid))) {
529 DEBUG(0, ("Could not find unix group %lu\n",
530 (unsigned long)map->gid));
531 //return NT_STATUS_NO_SUCH_GROUP;
532 TALLOC_FREE(map);
533 return -1;
536 TALLOC_FREE(map);
538 DEBUG(0,("Group members of %s: ", grp->gr_name));
540 if ( !(member = samu_new(talloc_tos())) ) {
541 //return NT_STATUS_NO_MEMORY;
542 return -1;
545 if (!pdb_getsampwsid(member, &member_sid)) {
546 DEBUG(1, ("Found bogus group member: (member_sid=%s group=%s)\n",
547 dom_sid_str_buf(&member_sid, &buf1),
548 grp->gr_name));
549 TALLOC_FREE(member);
550 return -1;
553 if (pdb_get_group_rid(member) == rid) {
554 DEBUGADD(0,("%s(primary),", pdb_get_username(member)));
555 TALLOC_FREE(member);
556 return -1;
559 DEBUGADD(0,("%s,", pdb_get_username(member)));
560 nt_member = talloc_strdup(talloc_tos(), pdb_get_username(member));
561 TALLOC_FREE(member);
563 DEBUGADD(0,("\n"));
565 unix_members = grp->gr_mem;
567 while (*unix_members) {
568 if (strcmp(*unix_members, nt_member) == 0) {
569 is_unix_member = true;
570 break;
572 unix_members += 1;
575 if (!is_unix_member && mem->active) {
576 smb_add_user_group(grp->gr_name, nt_member);
577 } else if (is_unix_member && !mem->active) {
578 smb_delete_user_group(grp->gr_name, nt_member);
581 return 0;
584 static int dssync_passdb_traverse_groups(struct db_record *rec,
585 void *private_data)
587 struct dssync_passdb_traverse_groups *state =
588 (struct dssync_passdb_traverse_groups *)private_data;
589 struct dssync_passdb *pctx =
590 talloc_get_type_abort(state->ctx->private_data,
591 struct dssync_passdb);
592 struct dssync_passdb_traverse_gmembers mstate;
593 struct dssync_passdb_obj *obj;
594 TDB_DATA value;
595 NTSTATUS status;
597 state->idx++;
598 if (pctx->methods == NULL) {
599 return -1;
602 value = dbwrap_record_get_value(rec);
604 obj = dssync_parse_obj(value);
605 if (obj == NULL) {
606 return -1;
609 ZERO_STRUCT(mstate);
610 mstate.ctx = state->ctx;
611 mstate.name = "members";
612 mstate.obj = obj;
613 status = dbwrap_traverse_read(obj->members,
614 dssync_passdb_traverse_gmembers,
615 &mstate, NULL);
616 if (!NT_STATUS_IS_OK(status)) {
617 return -1;
620 return 0;
623 static NTSTATUS passdb_finish(struct dssync_context *ctx, TALLOC_CTX *mem_ctx,
624 struct replUpToDateVectorBlob *new_utdv)
626 struct dssync_passdb *pctx =
627 talloc_get_type_abort(ctx->private_data,
628 struct dssync_passdb);
629 struct dssync_passdb_traverse_aliases astate;
630 struct dssync_passdb_traverse_groups gstate;
631 NTSTATUS status;
633 ZERO_STRUCT(astate);
634 astate.ctx = ctx;
635 astate.name = "aliases";
636 status = dbwrap_traverse_read(pctx->aliases,
637 dssync_passdb_traverse_aliases,
638 &astate, NULL);
639 if (!NT_STATUS_IS_OK(status)) {
640 return NT_STATUS_INTERNAL_ERROR;
643 ZERO_STRUCT(gstate);
644 gstate.ctx = ctx;
645 gstate.name = "groups";
646 status = dbwrap_traverse_read(pctx->groups,
647 dssync_passdb_traverse_groups,
648 &gstate, NULL);
649 if (!NT_STATUS_IS_OK(status)) {
650 return NT_STATUS_INTERNAL_ERROR;
653 TALLOC_FREE(pctx->methods);
654 TALLOC_FREE(pctx);
656 return NT_STATUS_OK;
659 /****************************************************************
660 ****************************************************************/
662 static NTSTATUS smb_create_user(TALLOC_CTX *mem_ctx,
663 uint32_t acct_flags,
664 const char *account,
665 struct passwd **passwd_p)
667 const struct loadparm_substitution *lp_sub =
668 loadparm_s3_global_substitution();
669 struct passwd *passwd;
670 char *add_script = NULL;
672 passwd = Get_Pwnam_alloc(mem_ctx, account);
673 if (passwd) {
674 *passwd_p = passwd;
675 return NT_STATUS_OK;
678 /* Create appropriate user */
679 if (acct_flags & ACB_NORMAL) {
680 add_script = lp_add_user_script(mem_ctx, lp_sub);
681 } else if ( (acct_flags & ACB_WSTRUST) ||
682 (acct_flags & ACB_SVRTRUST) ||
683 (acct_flags & ACB_DOMTRUST) ) {
684 add_script = lp_add_machine_script(mem_ctx, lp_sub);
685 } else {
686 DEBUG(1, ("Unknown user type: %s\n",
687 pdb_encode_acct_ctrl(acct_flags, NEW_PW_FORMAT_SPACE_PADDED_LEN)));
688 return NT_STATUS_UNSUCCESSFUL;
691 if (!add_script) {
692 return NT_STATUS_NO_MEMORY;
695 if (*add_script) {
696 int add_ret;
697 add_script = talloc_all_string_sub(mem_ctx, add_script,
698 "%u", account);
699 if (!add_script) {
700 return NT_STATUS_NO_MEMORY;
702 add_ret = smbrun(add_script, NULL, NULL);
703 DEBUG(add_ret ? 0 : 1,("fetch_account: Running the command `%s' "
704 "gave %d\n", add_script, add_ret));
705 if (add_ret == 0) {
706 smb_nscd_flush_user_cache();
710 /* try and find the possible unix account again */
711 passwd = Get_Pwnam_alloc(mem_ctx, account);
712 if (!passwd) {
713 return NT_STATUS_NO_SUCH_USER;
716 *passwd_p = passwd;
718 return NT_STATUS_OK;
721 static struct drsuapi_DsReplicaAttribute *find_drsuapi_attr(
722 const struct drsuapi_DsReplicaObjectListItemEx *cur,
723 uint32_t attid)
725 uint32_t i = 0;
727 for (i = 0; i < cur->object.attribute_ctr.num_attributes; i++) {
728 struct drsuapi_DsReplicaAttribute *attr;
730 attr = &cur->object.attribute_ctr.attributes[i];
732 if (attr->attid == attid) {
733 return attr;
737 return NULL;
740 static NTSTATUS find_drsuapi_attr_string(TALLOC_CTX *mem_ctx,
741 const struct drsuapi_DsReplicaObjectListItemEx *cur,
742 uint32_t attid,
743 uint32_t *_count,
744 char ***_array)
746 struct drsuapi_DsReplicaAttribute *attr;
747 char **array;
748 uint32_t a;
750 attr = find_drsuapi_attr(cur, attid);
751 if (attr == NULL) {
752 return NT_STATUS_PROPSET_NOT_FOUND;
755 array = talloc_array(mem_ctx, char *, attr->value_ctr.num_values);
756 if (array == NULL) {
757 return NT_STATUS_NO_MEMORY;
760 for (a = 0; a < attr->value_ctr.num_values; a++) {
761 const DATA_BLOB *blob;
762 ssize_t ret;
764 blob = attr->value_ctr.values[a].blob;
766 if (blob == NULL) {
767 return NT_STATUS_INTERNAL_DB_CORRUPTION;
770 ret = pull_string_talloc(array, NULL, 0, &array[a],
771 blob->data, blob->length,
772 STR_UNICODE);
773 if (ret == -1) {
774 //TODO
775 return NT_STATUS_INTERNAL_ERROR;
779 *_count = attr->value_ctr.num_values;
780 *_array = array;
781 return NT_STATUS_OK;
784 static NTSTATUS find_drsuapi_attr_int32(TALLOC_CTX *mem_ctx,
785 const struct drsuapi_DsReplicaObjectListItemEx *cur,
786 uint32_t attid,
787 uint32_t *_count,
788 int32_t **_array)
790 struct drsuapi_DsReplicaAttribute *attr;
791 int32_t *array;
792 uint32_t a;
794 attr = find_drsuapi_attr(cur, attid);
795 if (attr == NULL) {
796 return NT_STATUS_PROPSET_NOT_FOUND;
799 array = talloc_array(mem_ctx, int32_t, attr->value_ctr.num_values);
800 if (array == NULL) {
801 return NT_STATUS_NO_MEMORY;
804 for (a = 0; a < attr->value_ctr.num_values; a++) {
805 const DATA_BLOB *blob;
807 blob = attr->value_ctr.values[a].blob;
809 if (blob == NULL) {
810 return NT_STATUS_INTERNAL_DB_CORRUPTION;
813 if (blob->length != 4) {
814 return NT_STATUS_INTERNAL_DB_CORRUPTION;
817 array[a] = IVAL(blob->data, 0);
820 *_count = attr->value_ctr.num_values;
821 *_array = array;
822 return NT_STATUS_OK;
825 static NTSTATUS find_drsuapi_attr_blob(TALLOC_CTX *mem_ctx,
826 const struct drsuapi_DsReplicaObjectListItemEx *cur,
827 uint32_t attid,
828 uint32_t *_count,
829 DATA_BLOB **_array)
831 struct drsuapi_DsReplicaAttribute *attr;
832 DATA_BLOB *array;
833 uint32_t a;
835 attr = find_drsuapi_attr(cur, attid);
836 if (attr == NULL) {
837 return NT_STATUS_PROPSET_NOT_FOUND;
840 array = talloc_array(mem_ctx, DATA_BLOB, attr->value_ctr.num_values);
841 if (array == NULL) {
842 return NT_STATUS_NO_MEMORY;
845 for (a = 0; a < attr->value_ctr.num_values; a++) {
846 const DATA_BLOB *blob;
848 blob = attr->value_ctr.values[a].blob;
850 if (blob == NULL) {
851 return NT_STATUS_INTERNAL_DB_CORRUPTION;
854 array[a] = data_blob_talloc(array, blob->data, blob->length);
855 if (array[a].length != blob->length) {
856 return NT_STATUS_NO_MEMORY;
859 *_count = attr->value_ctr.num_values;
860 *_array = array;
861 return NT_STATUS_OK;
864 static NTSTATUS find_drsuapi_attr_int64(TALLOC_CTX *mem_ctx,
865 const struct drsuapi_DsReplicaObjectListItemEx *cur,
866 uint32_t attid,
867 uint32_t *_count,
868 int64_t **_array)
870 struct drsuapi_DsReplicaAttribute *attr;
871 int64_t *array;
872 uint32_t a;
874 attr = find_drsuapi_attr(cur, attid);
875 if (attr == NULL) {
876 return NT_STATUS_PROPSET_NOT_FOUND;
879 array = talloc_array(mem_ctx, int64_t, attr->value_ctr.num_values);
880 if (array == NULL) {
881 return NT_STATUS_NO_MEMORY;
884 for (a = 0; a < attr->value_ctr.num_values; a++) {
885 const DATA_BLOB *blob;
887 blob = attr->value_ctr.values[a].blob;
889 if (blob == NULL) {
890 return NT_STATUS_INTERNAL_DB_CORRUPTION;
893 if (blob->length != 8) {
894 return NT_STATUS_INTERNAL_DB_CORRUPTION;
897 array[a] = BVAL(blob->data, 0);
899 *_count = attr->value_ctr.num_values;
900 *_array = array;
901 return NT_STATUS_OK;
904 static NTSTATUS find_drsuapi_attr_dn(TALLOC_CTX *mem_ctx,
905 const struct drsuapi_DsReplicaObjectListItemEx *cur,
906 uint32_t attid,
907 uint32_t *_count,
908 struct drsuapi_DsReplicaObjectIdentifier3 **_array)
910 struct drsuapi_DsReplicaAttribute *attr;
911 struct drsuapi_DsReplicaObjectIdentifier3 *array;
912 uint32_t a;
914 attr = find_drsuapi_attr(cur, attid);
915 if (attr == NULL) {
916 return NT_STATUS_PROPSET_NOT_FOUND;
919 array = talloc_array(mem_ctx,
920 struct drsuapi_DsReplicaObjectIdentifier3,
921 attr->value_ctr.num_values);
922 if (array == NULL) {
923 return NT_STATUS_NO_MEMORY;
926 for (a = 0; a < attr->value_ctr.num_values; a++) {
927 const DATA_BLOB *blob;
928 enum ndr_err_code ndr_err;
929 NTSTATUS status;
931 blob = attr->value_ctr.values[a].blob;
933 if (blob == NULL) {
934 return NT_STATUS_INTERNAL_DB_CORRUPTION;
937 /* windows sometimes sends an extra two pad bytes here */
938 ndr_err = ndr_pull_struct_blob(blob, array, &array[a],
939 (ndr_pull_flags_fn_t)ndr_pull_drsuapi_DsReplicaObjectIdentifier3);
940 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
941 status = ndr_map_error2ntstatus(ndr_err);
942 return status;
945 *_count = attr->value_ctr.num_values;
946 *_array = array;
947 return NT_STATUS_OK;
950 #define GET_BLOB_EX(attr, needed) do { \
951 NTSTATUS _status; \
952 uint32_t _cnt; \
953 DATA_BLOB *_vals = NULL; \
954 attr = data_blob_null; \
955 _status = find_drsuapi_attr_blob(mem_ctx, cur, \
956 DRSUAPI_ATTID_ ## attr, \
957 &_cnt, &_vals); \
958 if (NT_STATUS_EQUAL(_status, NT_STATUS_PROPSET_NOT_FOUND)) { \
959 if (!needed) { \
960 _status = NT_STATUS_OK; \
961 _cnt = 0; \
964 if (!NT_STATUS_IS_OK(_status)) { \
965 DEBUG(0,(__location__ "attr[%s] %s\n", \
966 #attr, nt_errstr(_status))); \
967 return _status; \
969 if (_cnt == 0) { \
970 if (needed) { \
971 talloc_free(_vals); \
972 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
973 return NT_STATUS_OBJECT_NAME_NOT_FOUND; \
975 } else if (_cnt > 1) { \
976 talloc_free(_vals); \
977 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
978 return NT_STATUS_INTERNAL_DB_CORRUPTION; \
979 } else { \
980 attr = _vals[0]; \
981 (void)talloc_steal(mem_ctx, _vals[0].data); \
983 talloc_free(_vals); \
984 } while(0)
986 #define GET_STRING_EX(attr, needed) do { \
987 NTSTATUS _status; \
988 uint32_t _cnt; \
989 char **_vals = NULL; \
990 attr = NULL; \
991 _status = find_drsuapi_attr_string(mem_ctx, cur, \
992 DRSUAPI_ATTID_ ## attr, \
993 &_cnt, &_vals); \
994 if (NT_STATUS_EQUAL(_status, NT_STATUS_PROPSET_NOT_FOUND)) { \
995 if (!needed) { \
996 _status = NT_STATUS_OK; \
997 _cnt = 0; \
1000 if (!NT_STATUS_IS_OK(_status)) { \
1001 DEBUG(0,(__location__ "attr[%s] %s\n", \
1002 #attr, nt_errstr(_status))); \
1003 return _status; \
1005 if (_cnt == 0) { \
1006 if (needed) { \
1007 talloc_free(_vals); \
1008 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1009 return NT_STATUS_OBJECT_NAME_NOT_FOUND; \
1011 } else if (_cnt > 1) { \
1012 talloc_free(_vals); \
1013 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1014 return NT_STATUS_INTERNAL_DB_CORRUPTION; \
1015 } else { \
1016 attr = talloc_move(mem_ctx, &_vals[0]); \
1018 talloc_free(_vals); \
1019 } while(0)
1021 #define GET_UINT32_EX(attr, needed) do { \
1022 NTSTATUS _status; \
1023 uint32_t _cnt; \
1024 int32_t*_vals = NULL; \
1025 attr = 0; \
1026 _status = find_drsuapi_attr_int32(mem_ctx, cur, \
1027 DRSUAPI_ATTID_ ## attr, \
1028 &_cnt, &_vals); \
1029 if (NT_STATUS_EQUAL(_status, NT_STATUS_PROPSET_NOT_FOUND)) { \
1030 if (!needed) { \
1031 _status = NT_STATUS_OK; \
1032 _cnt = 0; \
1035 if (!NT_STATUS_IS_OK(_status)) { \
1036 DEBUG(0,(__location__ "attr[%s] %s\n", \
1037 #attr, nt_errstr(_status))); \
1038 return _status; \
1040 if (_cnt == 0) { \
1041 if (needed) { \
1042 talloc_free(_vals); \
1043 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1044 return NT_STATUS_OBJECT_NAME_NOT_FOUND; \
1046 } else if (_cnt > 1) { \
1047 talloc_free(_vals); \
1048 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1049 return NT_STATUS_INTERNAL_DB_CORRUPTION; \
1050 } else { \
1051 attr = (uint32_t)_vals[0]; \
1053 talloc_free(_vals); \
1054 } while(0)
1056 #define GET_UINT64_EX(attr, needed) do { \
1057 NTSTATUS _status; \
1058 uint32_t _cnt; \
1059 int64_t *_vals = NULL; \
1060 attr = 0; \
1061 _status = find_drsuapi_attr_int64(mem_ctx, cur, \
1062 DRSUAPI_ATTID_ ## attr, \
1063 &_cnt, &_vals); \
1064 if (NT_STATUS_EQUAL(_status, NT_STATUS_PROPSET_NOT_FOUND)) { \
1065 if (!needed) { \
1066 _status = NT_STATUS_OK; \
1067 _cnt = 0; \
1070 if (!NT_STATUS_IS_OK(_status)) { \
1071 DEBUG(0,(__location__ "attr[%s] %s\n", \
1072 #attr, nt_errstr(_status))); \
1073 return _status; \
1075 if (_cnt == 0) { \
1076 if (needed) { \
1077 talloc_free(_vals); \
1078 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1079 return NT_STATUS_OBJECT_NAME_NOT_FOUND; \
1081 } else if (_cnt > 1) { \
1082 talloc_free(_vals); \
1083 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1084 return NT_STATUS_INTERNAL_DB_CORRUPTION; \
1085 } else { \
1086 attr = (uint64_t)_vals[0]; \
1088 talloc_free(_vals); \
1089 } while(0)
1091 #define GET_BLOB(attr) GET_BLOB_EX(attr, false)
1092 #define GET_STRING(attr) GET_STRING_EX(attr, false)
1093 #define GET_UINT32(attr) GET_UINT32_EX(attr, false)
1094 #define GET_UINT64(attr) GET_UINT64_EX(attr, false)
1096 /* Convert a struct samu_DELTA to a struct samu. */
1097 #define STRING_CHANGED (old_string && !new_string) ||\
1098 (!old_string && new_string) ||\
1099 (old_string && new_string && (strcmp(old_string, new_string) != 0))
1101 #define STRING_CHANGED_NC(s1,s2) ((s1) && !(s2)) ||\
1102 (!(s1) && (s2)) ||\
1103 ((s1) && (s2) && (strcmp((s1), (s2)) != 0))
1105 /****************************************************************
1106 ****************************************************************/
1108 static NTSTATUS sam_account_from_object(struct samu *account,
1109 struct drsuapi_DsReplicaObjectListItemEx *cur)
1111 TALLOC_CTX *mem_ctx = account;
1112 const char *old_string, *new_string;
1113 struct dom_sid_buf buf;
1114 time_t unix_time, stored_time;
1115 NTSTATUS status;
1117 NTTIME lastLogon;
1118 NTTIME lastLogoff;
1119 NTTIME pwdLastSet;
1120 NTTIME accountExpires;
1121 const char *sAMAccountName;
1122 const char *displayName;
1123 const char *homeDirectory;
1124 const char *homeDrive;
1125 const char *scriptPath;
1126 const char *profilePath;
1127 const char *description;
1128 const char *userWorkstations;
1129 DATA_BLOB userParameters;
1130 struct dom_sid objectSid;
1131 uint32_t primaryGroupID;
1132 uint32_t userAccountControl;
1133 DATA_BLOB logonHours;
1134 uint32_t badPwdCount;
1135 uint32_t logonCount;
1136 DATA_BLOB unicodePwd;
1137 DATA_BLOB dBCSPwd;
1139 uint32_t rid = 0;
1140 uint32_t acct_flags;
1141 uint32_t units_per_week;
1143 objectSid = cur->object.identifier->sid;
1144 GET_STRING_EX(sAMAccountName, true);
1145 DEBUG(0,("sam_account_from_object(%s, %s) start\n",
1146 sAMAccountName,
1147 dom_sid_str_buf(&objectSid, &buf)));
1148 GET_UINT64(lastLogon);
1149 GET_UINT64(lastLogoff);
1150 GET_UINT64(pwdLastSet);
1151 GET_UINT64(accountExpires);
1152 GET_STRING(displayName);
1153 GET_STRING(homeDirectory);
1154 GET_STRING(homeDrive);
1155 GET_STRING(scriptPath);
1156 GET_STRING(profilePath);
1157 GET_STRING(description);
1158 GET_STRING(userWorkstations);
1159 GET_BLOB(userParameters);
1160 GET_UINT32(primaryGroupID);
1161 GET_UINT32(userAccountControl);
1162 GET_BLOB(logonHours);
1163 GET_UINT32(badPwdCount);
1164 GET_UINT32(logonCount);
1165 GET_BLOB(unicodePwd);
1166 GET_BLOB(dBCSPwd);
1168 status = dom_sid_split_rid(mem_ctx, &objectSid, NULL, &rid);
1169 if (!NT_STATUS_IS_OK(status)) {
1170 return status;
1172 acct_flags = ds_uf2acb(userAccountControl);
1174 /* Username, fullname, home dir, dir drive, logon script, acct
1175 desc, workstations, profile. */
1177 if (sAMAccountName) {
1178 old_string = pdb_get_nt_username(account);
1179 new_string = sAMAccountName;
1181 if (STRING_CHANGED) {
1182 pdb_set_nt_username(account, new_string, PDB_CHANGED);
1185 /* Unix username is the same - for sanity */
1186 old_string = pdb_get_username( account );
1187 if (STRING_CHANGED) {
1188 pdb_set_username(account, new_string, PDB_CHANGED);
1192 if (displayName) {
1193 old_string = pdb_get_fullname(account);
1194 new_string = displayName;
1196 if (STRING_CHANGED)
1197 pdb_set_fullname(account, new_string, PDB_CHANGED);
1200 if (homeDirectory) {
1201 old_string = pdb_get_homedir(account);
1202 new_string = homeDirectory;
1204 if (STRING_CHANGED)
1205 pdb_set_homedir(account, new_string, PDB_CHANGED);
1208 if (homeDrive) {
1209 old_string = pdb_get_dir_drive(account);
1210 new_string = homeDrive;
1212 if (STRING_CHANGED)
1213 pdb_set_dir_drive(account, new_string, PDB_CHANGED);
1216 if (scriptPath) {
1217 old_string = pdb_get_logon_script(account);
1218 new_string = scriptPath;
1220 if (STRING_CHANGED)
1221 pdb_set_logon_script(account, new_string, PDB_CHANGED);
1224 if (description) {
1225 old_string = pdb_get_acct_desc(account);
1226 new_string = description;
1228 if (STRING_CHANGED)
1229 pdb_set_acct_desc(account, new_string, PDB_CHANGED);
1232 if (userWorkstations) {
1233 old_string = pdb_get_workstations(account);
1234 new_string = userWorkstations;
1236 if (STRING_CHANGED)
1237 pdb_set_workstations(account, new_string, PDB_CHANGED);
1240 if (profilePath) {
1241 old_string = pdb_get_profile_path(account);
1242 new_string = profilePath;
1244 if (STRING_CHANGED)
1245 pdb_set_profile_path(account, new_string, PDB_CHANGED);
1248 if (userParameters.data) {
1249 char *newstr = NULL;
1250 old_string = pdb_get_munged_dial(account);
1252 if (userParameters.length != 0) {
1253 newstr = base64_encode_data_blob(talloc_tos(),
1254 userParameters);
1255 SMB_ASSERT(newstr != NULL);
1258 if (STRING_CHANGED_NC(old_string, newstr))
1259 pdb_set_munged_dial(account, newstr, PDB_CHANGED);
1260 TALLOC_FREE(newstr);
1263 /* User and group sid */
1264 if (rid != 0 && pdb_get_user_rid(account) != rid) {
1265 pdb_set_user_sid_from_rid(account, rid, PDB_CHANGED);
1267 if (primaryGroupID != 0 && pdb_get_group_rid(account) != primaryGroupID) {
1268 pdb_set_group_sid_from_rid(account, primaryGroupID, PDB_CHANGED);
1271 /* Logon and password information */
1272 if (!nt_time_is_zero(&lastLogon)) {
1273 unix_time = nt_time_to_unix(lastLogon);
1274 stored_time = pdb_get_logon_time(account);
1275 if (stored_time != unix_time)
1276 pdb_set_logon_time(account, unix_time, PDB_CHANGED);
1279 if (!nt_time_is_zero(&lastLogoff)) {
1280 unix_time = nt_time_to_unix(lastLogoff);
1281 stored_time = pdb_get_logoff_time(account);
1282 if (stored_time != unix_time)
1283 pdb_set_logoff_time(account, unix_time,PDB_CHANGED);
1286 /* Logon Divs */
1287 units_per_week = logonHours.length * 8;
1289 if (pdb_get_logon_divs(account) != units_per_week) {
1290 pdb_set_logon_divs(account, units_per_week, PDB_CHANGED);
1293 /* Logon Hours Len */
1294 if (units_per_week/8 != pdb_get_hours_len(account)) {
1295 pdb_set_hours_len(account, units_per_week/8, PDB_CHANGED);
1298 /* Logon Hours */
1299 if (logonHours.data) {
1300 char oldstr[44], newstr[44];
1301 pdb_sethexhours(oldstr, pdb_get_hours(account));
1302 pdb_sethexhours(newstr, logonHours.data);
1303 if (!strequal(oldstr, newstr)) {
1304 pdb_set_hours(account, logonHours.data,
1305 logonHours.length, PDB_CHANGED);
1309 if (pdb_get_bad_password_count(account) != badPwdCount)
1310 pdb_set_bad_password_count(account, badPwdCount, PDB_CHANGED);
1312 if (pdb_get_logon_count(account) != logonCount)
1313 pdb_set_logon_count(account, logonCount, PDB_CHANGED);
1315 if (!nt_time_is_zero(&pwdLastSet)) {
1316 unix_time = nt_time_to_unix(pwdLastSet);
1317 stored_time = pdb_get_pass_last_set_time(account);
1318 if (stored_time != unix_time)
1319 pdb_set_pass_last_set_time(account, unix_time, PDB_CHANGED);
1320 } else {
1321 /* no last set time, make it now */
1322 pdb_set_pass_last_set_time(account, time(NULL), PDB_CHANGED);
1325 if (!nt_time_is_zero(&accountExpires)) {
1326 unix_time = nt_time_to_unix(accountExpires);
1327 stored_time = pdb_get_kickoff_time(account);
1328 if (stored_time != unix_time)
1329 pdb_set_kickoff_time(account, unix_time, PDB_CHANGED);
1332 /* Decode hashes from password hash
1333 Note that win2000 may send us all zeros for the hashes if it doesn't
1334 think this channel is secure enough - don't set the passwords at all
1335 in that case
1337 if (dBCSPwd.length == 16 && !all_zero(dBCSPwd.data, 16)) {
1338 pdb_set_lanman_passwd(account, dBCSPwd.data, PDB_CHANGED);
1341 if (unicodePwd.length == 16 && !all_zero(unicodePwd.data, 16)) {
1342 pdb_set_nt_passwd(account, unicodePwd.data, PDB_CHANGED);
1345 /* TODO: history */
1347 /* TODO: account expiry time */
1349 pdb_set_acct_ctrl(account, acct_flags, PDB_CHANGED);
1351 pdb_set_domain(account, lp_workgroup(), PDB_CHANGED);
1353 DEBUG(0,("sam_account_from_object(%s, %s) done\n",
1354 sAMAccountName,
1355 dom_sid_str_buf(&objectSid, &buf)));
1356 return NT_STATUS_OK;
1359 /****************************************************************
1360 ****************************************************************/
1362 static NTSTATUS handle_account_object(struct dssync_passdb *pctx,
1363 TALLOC_CTX *mem_ctx,
1364 struct dssync_passdb_obj *obj)
1366 struct drsuapi_DsReplicaObjectListItemEx *cur = obj->cur;
1367 NTSTATUS status;
1368 fstring account;
1369 struct samu *sam_account=NULL;
1370 GROUP_MAP *map;
1371 struct group *grp;
1372 struct dom_sid user_sid;
1373 struct dom_sid group_sid;
1374 struct dom_sid_buf buf;
1375 struct passwd *passwd = NULL;
1376 uint32_t acct_flags;
1377 uint32_t rid;
1379 const char *sAMAccountName;
1380 uint32_t userAccountControl;
1382 user_sid = cur->object.identifier->sid;
1383 GET_STRING_EX(sAMAccountName, true);
1384 GET_UINT32_EX(userAccountControl, true);
1386 status = dom_sid_split_rid(mem_ctx, &user_sid, NULL, &rid);
1387 if (!NT_STATUS_IS_OK(status)) {
1388 return status;
1391 fstrcpy(account, sAMAccountName);
1392 if (rid == DOMAIN_RID_GUEST) {
1394 * pdb_getsampwsid() has special handling for DOMAIN_RID_GUEST
1395 * that's why we need to ignore it here.
1397 * pdb_smbpasswd.c also has some DOMAIN_RID_GUEST related
1398 * code...
1400 DEBUG(0,("Ignore %s - %s\n",
1401 account,
1402 dom_sid_str_buf(&user_sid, &buf)));
1403 return NT_STATUS_OK;
1405 DEBUG(0,("Creating account: %s\n", account));
1407 if ( !(sam_account = samu_new(mem_ctx)) ) {
1408 return NT_STATUS_NO_MEMORY;
1411 acct_flags = ds_uf2acb(userAccountControl);
1412 status = smb_create_user(sam_account, acct_flags, account, &passwd);
1413 if (!NT_STATUS_IS_OK(status)) {
1414 DEBUG(0,("Could not create posix account info for '%s'- %s\n",
1415 account, nt_errstr(status)));
1416 TALLOC_FREE(sam_account);
1417 return status;
1420 DEBUG(3, ("Attempting to find SID %s for user %s in the passdb\n",
1421 dom_sid_str_buf(&user_sid, &buf),
1422 account));
1423 if (!pdb_getsampwsid(sam_account, &user_sid)) {
1424 sam_account_from_object(sam_account, cur);
1425 DEBUG(3, ("Attempting to add user SID %s for user %s in the passdb\n",
1426 dom_sid_str_buf(&user_sid, &buf),
1427 pdb_get_username(sam_account)));
1428 if (!NT_STATUS_IS_OK(pdb_add_sam_account(sam_account))) {
1429 DEBUG(1, ("SAM Account for %s failed to be added to the passdb!\n",
1430 account));
1431 TALLOC_FREE(sam_account);
1432 return NT_STATUS_ACCESS_DENIED;
1434 } else {
1435 sam_account_from_object(sam_account, cur);
1436 DEBUG(3, ("Attempting to update user SID %s for user %s in the passdb\n",
1437 dom_sid_str_buf(&user_sid, &buf),
1438 pdb_get_username(sam_account)));
1439 if (!NT_STATUS_IS_OK(pdb_update_sam_account(sam_account))) {
1440 DEBUG(1, ("SAM Account for %s failed to be updated in the passdb!\n",
1441 account));
1442 TALLOC_FREE(sam_account);
1443 return NT_STATUS_ACCESS_DENIED;
1447 if (pdb_get_group_sid(sam_account) == NULL) {
1448 TALLOC_FREE(sam_account);
1449 return NT_STATUS_UNSUCCESSFUL;
1452 group_sid = *pdb_get_group_sid(sam_account);
1454 map = talloc_zero(NULL, GROUP_MAP);
1455 if (!map) {
1456 return NT_STATUS_NO_MEMORY;
1459 if (!pdb_getgrsid(map, group_sid)) {
1460 DEBUG(0, ("Primary group of %s has no mapping!\n",
1461 pdb_get_username(sam_account)));
1462 } else {
1463 if (map->gid != passwd->pw_gid) {
1464 if (!(grp = getgrgid(map->gid))) {
1465 DEBUG(0, ("Could not find unix group %lu for user %s (group SID=%s)\n",
1466 (unsigned long)map->gid, pdb_get_username(sam_account),
1467 dom_sid_str_buf(&group_sid, &buf)));
1468 } else {
1469 smb_set_primary_group(grp->gr_name, pdb_get_username(sam_account));
1474 TALLOC_FREE(map);
1476 if ( !passwd ) {
1477 DEBUG(1, ("No unix user for this account (%s), cannot adjust mappings\n",
1478 pdb_get_username(sam_account)));
1481 TALLOC_FREE(sam_account);
1482 return NT_STATUS_OK;
1485 /****************************************************************
1486 ****************************************************************/
1488 static NTSTATUS handle_alias_object(struct dssync_passdb *pctx,
1489 TALLOC_CTX *mem_ctx,
1490 struct dssync_passdb_obj *obj)
1492 struct drsuapi_DsReplicaObjectListItemEx *cur = obj->cur;
1493 NTSTATUS status;
1494 struct group *grp = NULL;
1495 struct dom_sid group_sid;
1496 uint32_t rid = 0;
1497 struct dom_sid *dom_sid = NULL;
1498 struct dom_sid_buf sid_str;
1499 GROUP_MAP *map;
1500 bool insert = true;
1502 const char *sAMAccountName;
1503 const char *description;
1504 uint32_t i;
1505 uint32_t num_members = 0;
1506 struct drsuapi_DsReplicaObjectIdentifier3 *members = NULL;
1508 group_sid = cur->object.identifier->sid;
1509 GET_STRING_EX(sAMAccountName, true);
1510 GET_STRING(description);
1512 status = find_drsuapi_attr_dn(obj, cur, DRSUAPI_ATTID_member,
1513 &num_members, &members);
1514 if (NT_STATUS_EQUAL(status, NT_STATUS_PROPSET_NOT_FOUND)) {
1515 status = NT_STATUS_OK;
1517 if (!NT_STATUS_IS_OK(status)) {
1518 return status;
1521 dom_sid_split_rid(mem_ctx, &group_sid, &dom_sid, &rid);
1523 map = talloc_zero(mem_ctx, GROUP_MAP);
1524 if (map == NULL) {
1525 status = NT_STATUS_NO_MEMORY;
1526 goto done;
1529 map->nt_name = talloc_strdup(map, sAMAccountName);
1530 if (map->nt_name == NULL) {
1531 status = NT_STATUS_NO_MEMORY;
1532 goto done;
1535 if (description) {
1536 map->comment = talloc_strdup(map, description);
1537 } else {
1538 map->comment = talloc_strdup(map, "");
1540 if (map->comment == NULL) {
1541 status = NT_STATUS_NO_MEMORY;
1542 goto done;
1545 DEBUG(0,("Creating alias[%s] - %s members[%u]\n",
1546 map->nt_name,
1547 dom_sid_str_buf(&group_sid, &sid_str),
1548 num_members));
1550 status = dssync_insert_obj(pctx, pctx->aliases, obj);
1551 if (!NT_STATUS_IS_OK(status)) {
1552 goto done;
1555 if (pdb_getgrsid(map, group_sid)) {
1556 if (map->gid != -1) {
1557 grp = getgrgid(map->gid);
1559 insert = false;
1562 if (grp == NULL) {
1563 gid_t gid;
1565 /* No group found from mapping, find it from its name. */
1566 if ((grp = getgrnam(map->nt_name)) == NULL) {
1568 /* No appropriate group found, create one */
1570 DEBUG(0, ("Creating unix group: '%s'\n",
1571 map->nt_name));
1573 if (smb_create_group(map->nt_name, &gid) != 0) {
1574 status = NT_STATUS_ACCESS_DENIED;
1575 goto done;
1578 if ((grp = getgrgid(gid)) == NULL) {
1579 status = NT_STATUS_ACCESS_DENIED;
1580 goto done;
1585 map->gid = grp->gr_gid;
1586 map->sid = group_sid;
1588 if (dom_sid_equal(dom_sid, &global_sid_Builtin)) {
1590 * pdb_ldap does not like SID_NAME_WKN_GRP...
1592 * map.sid_name_use = SID_NAME_WKN_GRP;
1594 map->sid_name_use = SID_NAME_ALIAS;
1595 } else {
1596 map->sid_name_use = SID_NAME_ALIAS;
1599 if (insert) {
1600 pdb_add_group_mapping_entry(map);
1601 } else {
1602 pdb_update_group_mapping_entry(map);
1605 for (i=0; i < num_members; i++) {
1606 struct dssync_passdb_mem *mem;
1608 status = dssync_create_mem(pctx, obj,
1609 true /* active */,
1610 &members[i], &mem);
1611 if (!NT_STATUS_IS_OK(status)) {
1612 goto done;
1616 status = NT_STATUS_OK;
1618 done:
1619 TALLOC_FREE(map);
1620 return status;
1623 /****************************************************************
1624 ****************************************************************/
1626 static NTSTATUS handle_group_object(struct dssync_passdb *pctx,
1627 TALLOC_CTX *mem_ctx,
1628 struct dssync_passdb_obj *obj)
1630 struct drsuapi_DsReplicaObjectListItemEx *cur = obj->cur;
1631 NTSTATUS status;
1632 struct group *grp = NULL;
1633 struct dom_sid group_sid;
1634 struct dom_sid_buf sid_str;
1635 GROUP_MAP *map;
1636 bool insert = true;
1638 const char *sAMAccountName;
1639 const char *description;
1640 uint32_t i;
1641 uint32_t num_members = 0;
1642 struct drsuapi_DsReplicaObjectIdentifier3 *members = NULL;
1644 group_sid = cur->object.identifier->sid;
1645 GET_STRING_EX(sAMAccountName, true);
1646 GET_STRING(description);
1648 status = find_drsuapi_attr_dn(obj, cur, DRSUAPI_ATTID_member,
1649 &num_members, &members);
1650 if (NT_STATUS_EQUAL(status, NT_STATUS_PROPSET_NOT_FOUND)) {
1651 status = NT_STATUS_OK;
1653 if (!NT_STATUS_IS_OK(status)) {
1654 return status;
1657 map = talloc_zero(NULL, GROUP_MAP);
1658 if (!map) {
1659 return NT_STATUS_NO_MEMORY;
1662 map->nt_name = talloc_strdup(map, sAMAccountName);
1663 if (!map->nt_name) {
1664 status = NT_STATUS_NO_MEMORY;
1665 goto done;
1667 if (description) {
1668 map->comment = talloc_strdup(map, description);
1669 } else {
1670 map->comment = talloc_strdup(map, "");
1672 if (!map->comment) {
1673 status = NT_STATUS_NO_MEMORY;
1674 goto done;
1677 DEBUG(0,("Creating group[%s] - %s members [%u]\n",
1678 map->nt_name,
1679 dom_sid_str_buf(&group_sid, &sid_str),
1680 num_members));
1682 status = dssync_insert_obj(pctx, pctx->groups, obj);
1683 if (!NT_STATUS_IS_OK(status)) {
1684 goto done;
1687 if (pdb_getgrsid(map, group_sid)) {
1688 if (map->gid != -1) {
1689 grp = getgrgid(map->gid);
1691 insert = false;
1694 if (grp == NULL) {
1695 gid_t gid;
1697 /* No group found from mapping, find it from its name. */
1698 if ((grp = getgrnam(map->nt_name)) == NULL) {
1700 /* No appropriate group found, create one */
1702 DEBUG(0, ("Creating unix group: '%s'\n",
1703 map->nt_name));
1705 if (smb_create_group(map->nt_name, &gid) != 0) {
1706 status = NT_STATUS_ACCESS_DENIED;
1707 goto done;
1710 if ((grp = getgrnam(map->nt_name)) == NULL) {
1711 status = NT_STATUS_ACCESS_DENIED;
1712 goto done;
1717 map->gid = grp->gr_gid;
1718 map->sid = group_sid;
1719 map->sid_name_use = SID_NAME_DOM_GRP;
1721 if (insert) {
1722 pdb_add_group_mapping_entry(map);
1723 } else {
1724 pdb_update_group_mapping_entry(map);
1727 for (i=0; i < num_members; i++) {
1728 struct dssync_passdb_mem *mem;
1730 status = dssync_create_mem(pctx, obj,
1731 true /* active */,
1732 &members[i], &mem);
1733 if (!NT_STATUS_IS_OK(status)) {
1734 goto done;
1738 status = NT_STATUS_OK;
1740 done:
1741 TALLOC_FREE(map);
1742 return status;
1745 /****************************************************************
1746 ****************************************************************/
1748 static NTSTATUS handle_interdomain_trust_object(struct dssync_passdb *pctx,
1749 TALLOC_CTX *mem_ctx,
1750 struct dssync_passdb_obj *obj)
1752 struct drsuapi_DsReplicaObjectListItemEx *cur = obj->cur;
1753 DEBUG(0,("trust: %s\n", cur->object.identifier->dn));
1754 return NT_STATUS_NOT_IMPLEMENTED;
1757 /****************************************************************
1758 ****************************************************************/
1760 struct dssync_object_table_t {
1761 uint32_t type;
1762 NTSTATUS (*fn) (struct dssync_passdb *pctx,
1763 TALLOC_CTX *mem_ctx,
1764 struct dssync_passdb_obj *obj);
1767 static const struct dssync_object_table_t dssync_object_table[] = {
1768 { ATYPE_NORMAL_ACCOUNT, handle_account_object },
1769 { ATYPE_WORKSTATION_TRUST, handle_account_object },
1770 { ATYPE_SECURITY_LOCAL_GROUP, handle_alias_object },
1771 { ATYPE_SECURITY_GLOBAL_GROUP, handle_group_object },
1772 { ATYPE_INTERDOMAIN_TRUST, handle_interdomain_trust_object },
1775 /****************************************************************
1776 ****************************************************************/
1778 static NTSTATUS parse_object(struct dssync_passdb *pctx,
1779 TALLOC_CTX *mem_ctx,
1780 struct drsuapi_DsReplicaObjectListItemEx *cur)
1782 NTSTATUS status = NT_STATUS_OK;
1783 DATA_BLOB *blob = NULL;
1784 uint32_t i = 0;
1785 size_t a = 0;
1787 char *name = NULL;
1788 uint32_t sam_type = 0;
1790 DEBUG(3, ("parsing object '%s'\n", cur->object.identifier->dn));
1792 for (i=0; i < cur->object.attribute_ctr.num_attributes; i++) {
1793 struct drsuapi_DsReplicaAttribute *attr =
1794 &cur->object.attribute_ctr.attributes[i];
1796 if (attr->value_ctr.num_values != 1) {
1797 continue;
1800 if (!attr->value_ctr.values[0].blob) {
1801 continue;
1804 blob = attr->value_ctr.values[0].blob;
1806 switch (attr->attid) {
1807 case DRSUAPI_ATTID_sAMAccountName:
1808 pull_string_talloc(mem_ctx, NULL, 0, &name,
1809 blob->data, blob->length,
1810 STR_UNICODE);
1811 break;
1812 case DRSUAPI_ATTID_sAMAccountType:
1813 sam_type = IVAL(blob->data, 0);
1814 break;
1815 default:
1816 break;
1820 for (a=0; a < ARRAY_SIZE(dssync_object_table); a++) {
1821 if (sam_type == dssync_object_table[a].type) {
1822 if (dssync_object_table[a].fn) {
1823 struct dssync_passdb_obj *obj = NULL;
1824 status = dssync_create_obj(pctx, pctx->all,
1825 sam_type, cur, &obj);
1826 if (!NT_STATUS_IS_OK(status)) {
1827 break;
1829 status = dssync_object_table[a].fn(pctx,
1830 mem_ctx,
1831 obj);
1832 break;
1837 return status;
1840 static NTSTATUS parse_link(struct dssync_passdb *pctx,
1841 TALLOC_CTX *mem_ctx,
1842 struct drsuapi_DsReplicaLinkedAttribute *cur)
1844 struct drsuapi_DsReplicaObjectIdentifier3 *id3;
1845 const DATA_BLOB *blob;
1846 enum ndr_err_code ndr_err;
1847 NTSTATUS status;
1848 bool active = false;
1849 struct dssync_passdb_mem *mem;
1850 struct dssync_passdb_obj *obj;
1852 if (cur->attid != DRSUAPI_ATTID_member) {
1853 return NT_STATUS_OK;
1856 if (cur->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE) {
1857 active = true;
1860 DEBUG(3, ("parsing link '%s' - %s\n",
1861 cur->identifier->dn, active?"adding":"deleting"));
1863 blob = cur->value.blob;
1865 if (blob == NULL) {
1866 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1869 obj = dssync_search_obj_by_guid(pctx, pctx->all, &cur->identifier->guid);
1870 if (obj == NULL) {
1871 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1874 id3 = talloc_zero(obj, struct drsuapi_DsReplicaObjectIdentifier3);
1875 if (id3 == NULL) {
1876 return NT_STATUS_NO_MEMORY;
1879 /* windows sometimes sends an extra two pad bytes here */
1880 ndr_err = ndr_pull_struct_blob(blob, id3, id3,
1881 (ndr_pull_flags_fn_t)ndr_pull_drsuapi_DsReplicaObjectIdentifier3);
1882 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1883 status = ndr_map_error2ntstatus(ndr_err);
1884 return status;
1887 status = dssync_create_mem(pctx, obj,
1888 active,
1889 id3, &mem);
1890 if (!NT_STATUS_IS_OK(status)) {
1891 return status;
1894 return NT_STATUS_OK;
1897 /****************************************************************
1898 ****************************************************************/
1900 static NTSTATUS passdb_process_objects(struct dssync_context *ctx,
1901 TALLOC_CTX *mem_ctx,
1902 struct drsuapi_DsReplicaObjectListItemEx *cur,
1903 struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr)
1905 NTSTATUS status = NT_STATUS_OK;
1906 struct dssync_passdb *pctx =
1907 talloc_get_type_abort(ctx->private_data,
1908 struct dssync_passdb);
1910 for (; cur; cur = cur->next_object) {
1911 status = parse_object(pctx, mem_ctx, cur);
1912 if (!NT_STATUS_IS_OK(status)) {
1913 goto out;
1917 out:
1918 return status;
1921 /****************************************************************
1922 ****************************************************************/
1924 static NTSTATUS passdb_process_links(struct dssync_context *ctx,
1925 TALLOC_CTX *mem_ctx,
1926 uint32_t count,
1927 struct drsuapi_DsReplicaLinkedAttribute *links,
1928 struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr)
1930 NTSTATUS status = NT_STATUS_OK;
1931 struct dssync_passdb *pctx =
1932 talloc_get_type_abort(ctx->private_data,
1933 struct dssync_passdb);
1934 uint32_t i;
1936 for (i = 0; i < count; i++) {
1937 status = parse_link(pctx, mem_ctx, &links[i]);
1938 if (!NT_STATUS_IS_OK(status)) {
1939 goto out;
1943 out:
1944 return status;
1947 /****************************************************************
1948 ****************************************************************/
1950 const struct dssync_ops libnet_dssync_passdb_ops = {
1951 .startup = passdb_startup,
1952 .process_objects = passdb_process_objects,
1953 .process_links = passdb_process_links,
1954 .finish = passdb_finish,