s3-libds: use already existing ../libds/common/flag_mapping.h header.
[ira/wip.git] / source3 / libnet / libnet_dssync_passdb.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Copyright (C) Guenther Deschner <gd@samba.org> 2008
5
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.
10
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.
15
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/>.
18 */
19
20 #include "includes.h"
21 #include "libnet/libnet_dssync.h"
22 #include "libnet/libnet_samsync.h"
23 #include "../libcli/security/security.h"
24 #include "../libds/common/flags.h"
25 #include "../librpc/gen_ndr/ndr_drsuapi.h"
26 #include "dbwrap.h"
27 #include "../libds/common/flag_mapping.h"
28
29 /****************************************************************
30 ****************************************************************/
31
32 struct dssync_passdb {
33         struct pdb_methods *methods;
34         struct db_context *all;
35         struct db_context *aliases;
36         struct db_context *groups;
37 };
38
39 struct dssync_passdb_obj {
40         struct dssync_passdb_obj *self;
41         uint32_t type;
42         struct drsuapi_DsReplicaObjectListItemEx *cur;
43         TDB_DATA key;
44         TDB_DATA data;
45         struct db_context *members;
46 };
47
48 struct dssync_passdb_mem {
49         struct dssync_passdb_mem *self;
50         bool active;
51         struct drsuapi_DsReplicaObjectIdentifier3 *cur;
52         struct dssync_passdb_obj *obj;
53         TDB_DATA key;
54         TDB_DATA data;
55 };
56
57 static NTSTATUS dssync_insert_obj(struct dssync_passdb *pctx,
58                                   struct db_context *db,
59                                   struct dssync_passdb_obj *obj)
60 {
61         NTSTATUS status;
62         struct db_record *rec;
63
64         rec = db->fetch_locked(db, talloc_tos(), obj->key);
65         if (rec == NULL) {
66                 return NT_STATUS_NO_MEMORY;
67         }
68         if (rec->value.dsize != 0) {
69                 abort();
70         }
71
72         status = rec->store(rec, obj->data, TDB_INSERT);
73         if (!NT_STATUS_IS_OK(status)) {
74                 TALLOC_FREE(rec);
75                 return status;
76         }
77         TALLOC_FREE(rec);
78         return NT_STATUS_OK;
79 }
80
81 static struct dssync_passdb_obj *dssync_parse_obj(const TDB_DATA data)
82 {
83         struct dssync_passdb_obj *obj;
84
85         if (data.dsize != sizeof(obj)) {
86                 return NULL;
87         }
88
89         /*
90          * we need to copy the pointer to avoid alignment problems
91          * on some systems.
92          */
93         memcpy(&obj, data.dptr, sizeof(obj));
94
95         return talloc_get_type_abort(obj, struct dssync_passdb_obj);
96 }
97
98 static struct dssync_passdb_obj *dssync_search_obj_by_guid(struct dssync_passdb *pctx,
99                                                            struct db_context *db,
100                                                            const struct GUID *guid)
101 {
102         struct dssync_passdb_obj *obj;
103         int ret;
104         TDB_DATA key;
105         TDB_DATA data;
106
107         key = make_tdb_data((const uint8_t *)(void *)guid,
108                              sizeof(*guid));
109
110         ret = db->fetch(db, talloc_tos(), key, &data);
111         if (ret != 0) {
112                 return NULL;
113         }
114
115         obj = dssync_parse_obj(data);
116         return obj;
117 }
118
119 static NTSTATUS dssync_create_obj(struct dssync_passdb *pctx,
120                                   struct db_context *db,
121                                   uint32_t type,
122                                   struct drsuapi_DsReplicaObjectListItemEx *cur,
123                                   struct dssync_passdb_obj **_obj)
124 {
125         NTSTATUS status;
126         struct dssync_passdb_obj *obj;
127
128         obj = talloc_zero(pctx, struct dssync_passdb_obj);
129         if (obj == NULL) {
130                 return NT_STATUS_NO_MEMORY;
131         }
132         obj->self = obj;
133         obj->cur = cur;
134         obj->type = type;
135         obj->key = make_tdb_data((const uint8_t *)(void *)&cur->object.identifier->guid,
136                                    sizeof(cur->object.identifier->guid));
137         obj->data = make_tdb_data((const uint8_t *)(void *)&obj->self,
138                                   sizeof(obj->self));
139
140         obj->members = db_open_rbt(obj);
141         if (obj->members == NULL) {
142                 return NT_STATUS_NO_MEMORY;
143         }
144
145         status = dssync_insert_obj(pctx, db, obj);
146         if (!NT_STATUS_IS_OK(status)) {
147                 TALLOC_FREE(obj);
148                 return status;
149         }
150         *_obj = obj;
151         return NT_STATUS_OK;
152 }
153
154 static NTSTATUS dssync_insert_mem(struct dssync_passdb *pctx,
155                                   struct dssync_passdb_obj *obj,
156                                   struct dssync_passdb_mem *mem)
157 {
158         NTSTATUS status;
159         struct db_record *rec;
160
161         rec = obj->members->fetch_locked(obj->members, talloc_tos(), mem->key);
162         if (rec == NULL) {
163                 return NT_STATUS_NO_MEMORY;
164         }
165         if (rec->value.dsize != 0) {
166                 abort();
167         }
168
169         status = rec->store(rec, mem->data, TDB_INSERT);
170         if (!NT_STATUS_IS_OK(status)) {
171                 TALLOC_FREE(rec);
172                 return status;
173         }
174         TALLOC_FREE(rec);
175         return NT_STATUS_OK;
176 }
177
178 static NTSTATUS dssync_create_mem(struct dssync_passdb *pctx,
179                                   struct dssync_passdb_obj *obj,
180                                   bool active,
181                                   struct drsuapi_DsReplicaObjectIdentifier3 *cur,
182                                   struct dssync_passdb_mem **_mem)
183 {
184         NTSTATUS status;
185         struct dssync_passdb_mem *mem;
186
187         mem = talloc_zero(pctx, struct dssync_passdb_mem);
188         if (mem == NULL) {
189                 return NT_STATUS_NO_MEMORY;
190         }
191         mem->self = mem;
192         mem->cur = cur;
193         mem->active = active;
194         mem->obj = NULL;
195         mem->key = make_tdb_data((const uint8_t *)(void *)&cur->guid,
196                                    sizeof(cur->guid));
197         mem->data = make_tdb_data((const uint8_t *)(void *)&mem->self,
198                                   sizeof(mem->self));
199
200         status = dssync_insert_mem(pctx, obj, mem);
201         if (!NT_STATUS_IS_OK(status)) {
202                 TALLOC_FREE(obj);
203                 return status;
204         }
205         *_mem = mem;
206         return NT_STATUS_OK;
207 }
208
209 static struct dssync_passdb_mem *dssync_parse_mem(const TDB_DATA data)
210 {
211         struct dssync_passdb_mem *mem;
212
213         if (data.dsize != sizeof(mem)) {
214                 return NULL;
215         }
216
217         /*
218          * we need to copy the pointer to avoid alignment problems
219          * on some systems.
220          */
221         memcpy(&mem, data.dptr, sizeof(mem));
222
223         return talloc_get_type_abort(mem, struct dssync_passdb_mem);
224 }
225
226 static NTSTATUS passdb_startup(struct dssync_context *ctx, TALLOC_CTX *mem_ctx,
227                                struct replUpToDateVectorBlob **pold_utdv)
228 {
229         NTSTATUS status;
230         struct dssync_passdb *pctx;
231
232         pctx = talloc_zero(mem_ctx, struct dssync_passdb);
233         if (pctx == NULL) {
234                 return NT_STATUS_NO_MEMORY;
235         }
236
237         if (ctx->output_filename) {
238                 status = make_pdb_method_name(&pctx->methods, ctx->output_filename);
239         } else {
240                 status = make_pdb_method_name(&pctx->methods, lp_passdb_backend());
241         }
242
243         if (!NT_STATUS_IS_OK(status)) {
244                 return status;
245         }
246
247         pctx->all = db_open_rbt(pctx);
248         if (pctx->all == NULL) {
249                 return NT_STATUS_NO_MEMORY;
250         }
251         pctx->aliases = db_open_rbt(pctx);
252         if (pctx->aliases == NULL) {
253                 return NT_STATUS_NO_MEMORY;
254         }
255         pctx->groups = db_open_rbt(pctx);
256         if (pctx->groups == NULL) {
257                 return NT_STATUS_NO_MEMORY;
258         }
259
260         ctx->private_data = pctx;
261
262         return status;
263 }
264
265 /****************************************************************
266 ****************************************************************/
267
268 struct dssync_passdb_traverse_amembers {
269         struct dssync_context *ctx;
270         struct dssync_passdb_obj *obj;
271         const char *name;
272         uint32_t idx;
273 };
274
275 struct dssync_passdb_traverse_aliases {
276         struct dssync_context *ctx;
277         const char *name;
278         uint32_t idx;
279 };
280
281 static int dssync_passdb_traverse_amembers(struct db_record *rec,
282                                            void *private_data)
283 {
284         struct dssync_passdb_traverse_amembers *state =
285                 (struct dssync_passdb_traverse_amembers *)private_data;
286         struct dssync_passdb *pctx =
287                 talloc_get_type_abort(state->ctx->private_data,
288                 struct dssync_passdb);
289         struct dssync_passdb_mem *mem;
290         NTSTATUS status;
291         struct dom_sid alias_sid;
292         struct dom_sid member_sid;
293         const char *member_dn;
294         size_t num_members;
295         size_t i;
296         struct dom_sid *members;
297         bool is_member = false;
298         const char *action;
299
300         state->idx++;
301
302         alias_sid = state->obj->cur->object.identifier->sid;
303
304         mem = dssync_parse_mem(rec->value);
305         if (mem == NULL) {
306                 return -1;
307         }
308
309         member_sid = mem->cur->sid;
310         member_dn = mem->cur->dn;
311
312         mem->obj = dssync_search_obj_by_guid(pctx, pctx->all, &mem->cur->guid);
313         if (mem->obj == NULL) {
314                 DEBUG(0,("alias[%s] member[%s] can't resolve member - ignoring\n",
315                          sid_string_dbg(&alias_sid),
316                          is_null_sid(&member_sid)?
317                          sid_string_dbg(&member_sid):
318                          member_dn));
319                 return 0;
320         }
321
322         switch (mem->obj->type) {
323         case ATYPE_DISTRIBUTION_LOCAL_GROUP:
324         case ATYPE_DISTRIBUTION_GLOBAL_GROUP:
325                 DEBUG(0, ("alias[%s] ignore distribution group [%s]\n",
326                           sid_string_dbg(&alias_sid),
327                           member_dn));
328                 return 0;
329         default:
330                 break;
331         }
332
333         DEBUG(0,("alias[%s] member[%s]\n",
334                  sid_string_dbg(&alias_sid),
335                  sid_string_dbg(&member_sid)));
336
337         status = pdb_enum_aliasmem(&alias_sid, talloc_tos(),
338                                    &members, &num_members);
339         if (!NT_STATUS_IS_OK(status)) {
340                 DEBUG(0, ("Could not find current alias members %s - %s\n",
341                           sid_string_dbg(&alias_sid),
342                           nt_errstr(status)));
343                 return -1;
344         }
345
346         for (i=0; i < num_members; i++) {
347                 bool match;
348
349                 match = dom_sid_equal(&members[i], &member_sid);
350                 if (match) {
351                         is_member = true;
352                         break;
353                 }
354         }
355
356         status = NT_STATUS_OK;
357         action = "none";
358         if (!is_member && mem->active) {
359                 action = "add";
360                 pdb_add_aliasmem(&alias_sid, &member_sid);
361         } else if (is_member && !mem->active) {
362                 action = "delete";
363                 pdb_del_aliasmem(&alias_sid, &member_sid);
364         }
365         if (!NT_STATUS_IS_OK(status)) {
366                 DEBUG(0, ("Could not %s %s as alias members of %s - %s\n",
367                           action,
368                           sid_string_dbg(&member_sid),
369                           sid_string_dbg(&alias_sid),
370                           nt_errstr(status)));
371                 return -1;
372         }
373
374         return 0;
375 }
376
377 static int dssync_passdb_traverse_aliases(struct db_record *rec,
378                                           void *private_data)
379 {
380         struct dssync_passdb_traverse_aliases *state =
381                 (struct dssync_passdb_traverse_aliases *)private_data;
382         struct dssync_passdb *pctx =
383                 talloc_get_type_abort(state->ctx->private_data,
384                 struct dssync_passdb);
385         struct dssync_passdb_traverse_amembers mstate;
386         struct dssync_passdb_obj *obj;
387         int ret;
388
389         state->idx++;
390         if (pctx->methods == NULL) {
391                 return -1;
392         }
393
394         obj = dssync_parse_obj(rec->value);
395         if (obj == NULL) {
396                 return -1;
397         }
398
399         ZERO_STRUCT(mstate);
400         mstate.ctx = state->ctx;
401         mstate.name = "members";
402         mstate.obj = obj;
403         ret = obj->members->traverse_read(obj->members,
404                                           dssync_passdb_traverse_amembers,
405                                           &mstate);
406         if (ret < 0) {
407                 return -1;
408         }
409
410         return 0;
411 }
412
413 struct dssync_passdb_traverse_gmembers {
414         struct dssync_context *ctx;
415         struct dssync_passdb_obj *obj;
416         const char *name;
417         uint32_t idx;
418 };
419
420 struct dssync_passdb_traverse_groups {
421         struct dssync_context *ctx;
422         const char *name;
423         uint32_t idx;
424 };
425
426 static int dssync_passdb_traverse_gmembers(struct db_record *rec,
427                                            void *private_data)
428 {
429         struct dssync_passdb_traverse_gmembers *state =
430                 (struct dssync_passdb_traverse_gmembers *)private_data;
431         struct dssync_passdb *pctx =
432                 talloc_get_type_abort(state->ctx->private_data,
433                 struct dssync_passdb);
434         struct dssync_passdb_mem *mem;
435         NTSTATUS status;
436         char *nt_member = NULL;
437         char **unix_members;
438         struct dom_sid group_sid;
439         struct dom_sid member_sid;
440         struct samu *member = NULL;
441         const char *member_dn = NULL;
442         GROUP_MAP map;
443         struct group *grp;
444         uint32_t rid;
445         bool is_unix_member = false;
446
447         state->idx++;
448
449         group_sid = state->obj->cur->object.identifier->sid;
450
451         status = dom_sid_split_rid(talloc_tos(), &group_sid, NULL, &rid);
452         if (!NT_STATUS_IS_OK(status)) {
453                 return -1;
454         }
455
456         mem = dssync_parse_mem(rec->value);
457         if (mem == NULL) {
458                 return -1;
459         }
460
461         member_sid = mem->cur->sid;
462         member_dn = mem->cur->dn;
463
464         mem->obj = dssync_search_obj_by_guid(pctx, pctx->all, &mem->cur->guid);
465         if (mem->obj == NULL) {
466                 DEBUG(0,("group[%s] member[%s] can't resolve member - ignoring\n",
467                          sid_string_dbg(&group_sid),
468                          is_null_sid(&member_sid)?
469                          sid_string_dbg(&member_sid):
470                          member_dn));
471                 return 0;
472         }
473
474         member_sid = mem->obj->cur->object.identifier->sid;
475         member_dn = mem->obj->cur->object.identifier->dn;
476
477         switch (mem->obj->type) {
478         case ATYPE_SECURITY_LOCAL_GROUP:
479         case ATYPE_SECURITY_GLOBAL_GROUP:
480                 DEBUG(0, ("Group[%s] ignore member group [%s]\n",
481                           sid_string_dbg(&group_sid),
482                           sid_string_dbg(&member_sid)));
483                 return 0;
484
485         case ATYPE_DISTRIBUTION_LOCAL_GROUP:
486         case ATYPE_DISTRIBUTION_GLOBAL_GROUP:
487                 DEBUG(0, ("Group[%s] ignore distribution group [%s]\n",
488                           sid_string_dbg(&group_sid),
489                           member_dn));
490                 return 0;
491         default:
492                 break;
493         }
494
495         if (!get_domain_group_from_sid(group_sid, &map)) {
496                 DEBUG(0, ("Could not find global group %s\n",
497                           sid_string_dbg(&group_sid)));
498                 //return NT_STATUS_NO_SUCH_GROUP;
499                 return -1;
500         }
501
502         if (!(grp = getgrgid(map.gid))) {
503                 DEBUG(0, ("Could not find unix group %lu\n", (unsigned long)map.gid));
504                 //return NT_STATUS_NO_SUCH_GROUP;
505                 return -1;
506         }
507
508         DEBUG(0,("Group members of %s: ", grp->gr_name));
509
510         if ( !(member = samu_new(talloc_tos())) ) {
511                 //return NT_STATUS_NO_MEMORY;
512                 return -1;
513         }
514
515         if (!pdb_getsampwsid(member, &member_sid)) {
516                 DEBUG(1, ("Found bogus group member: (member_sid=%s group=%s)\n",
517                           sid_string_tos(&member_sid), grp->gr_name));
518                 TALLOC_FREE(member);
519                 return -1;
520         }
521
522         if (pdb_get_group_rid(member) == rid) {
523                 DEBUGADD(0,("%s(primary),", pdb_get_username(member)));
524                 TALLOC_FREE(member);
525                 return -1;
526         }
527
528         DEBUGADD(0,("%s,", pdb_get_username(member)));
529         nt_member = talloc_strdup(talloc_tos(), pdb_get_username(member));
530         TALLOC_FREE(member);
531
532         DEBUGADD(0,("\n"));
533
534         unix_members = grp->gr_mem;
535
536         while (*unix_members) {
537                 if (strcmp(*unix_members, nt_member) == 0) {
538                         is_unix_member = true;
539                         break;
540                 }
541                 unix_members += 1;
542         }
543
544         if (!is_unix_member && mem->active) {
545                 smb_add_user_group(grp->gr_name, nt_member);
546         } else if (is_unix_member && !mem->active) {
547                 smb_delete_user_group(grp->gr_name, nt_member);
548         }
549
550         return 0;
551 }
552
553 static int dssync_passdb_traverse_groups(struct db_record *rec,
554                                          void *private_data)
555 {
556         struct dssync_passdb_traverse_groups *state =
557                 (struct dssync_passdb_traverse_groups *)private_data;
558         struct dssync_passdb *pctx =
559                 talloc_get_type_abort(state->ctx->private_data,
560                 struct dssync_passdb);
561         struct dssync_passdb_traverse_gmembers mstate;
562         struct dssync_passdb_obj *obj;
563         int ret;
564
565         state->idx++;
566         if (pctx->methods == NULL) {
567                 return -1;
568         }
569
570         obj = dssync_parse_obj(rec->value);
571         if (obj == NULL) {
572                 return -1;
573         }
574
575         ZERO_STRUCT(mstate);
576         mstate.ctx = state->ctx;
577         mstate.name = "members";
578         mstate.obj = obj;
579         ret = obj->members->traverse_read(obj->members,
580                                           dssync_passdb_traverse_gmembers,
581                                           &mstate);
582         if (ret < 0) {
583                 return -1;
584         }
585
586         return 0;
587 }
588
589 static NTSTATUS passdb_finish(struct dssync_context *ctx, TALLOC_CTX *mem_ctx,
590                               struct replUpToDateVectorBlob *new_utdv)
591 {
592         struct dssync_passdb *pctx =
593                 talloc_get_type_abort(ctx->private_data,
594                 struct dssync_passdb);
595         struct dssync_passdb_traverse_aliases astate;
596         struct dssync_passdb_traverse_groups gstate;
597         int ret;
598
599         ZERO_STRUCT(astate);
600         astate.ctx = ctx;
601         astate.name = "aliases";
602         ret = pctx->aliases->traverse_read(pctx->aliases,
603                                            dssync_passdb_traverse_aliases,
604                                            &astate);
605         if (ret < 0) {
606                 return NT_STATUS_INTERNAL_ERROR;
607         }
608
609         ZERO_STRUCT(gstate);
610         gstate.ctx = ctx;
611         gstate.name = "groups";
612         ret = pctx->groups->traverse_read(pctx->groups,
613                                           dssync_passdb_traverse_groups,
614                                           &gstate);
615         if (ret < 0) {
616                 return NT_STATUS_INTERNAL_ERROR;
617         }
618
619         TALLOC_FREE(pctx->methods);
620         TALLOC_FREE(pctx);
621
622         return NT_STATUS_OK;
623 }
624
625 /****************************************************************
626 ****************************************************************/
627
628 static NTSTATUS smb_create_user(TALLOC_CTX *mem_ctx,
629                                 uint32_t acct_flags,
630                                 const char *account,
631                                 struct passwd **passwd_p)
632 {
633         struct passwd *passwd;
634         char *add_script = NULL;
635
636         passwd = Get_Pwnam_alloc(mem_ctx, account);
637         if (passwd) {
638                 *passwd_p = passwd;
639                 return NT_STATUS_OK;
640         }
641
642         /* Create appropriate user */
643         if (acct_flags & ACB_NORMAL) {
644                 add_script = talloc_strdup(mem_ctx, lp_adduser_script());
645         } else if ( (acct_flags & ACB_WSTRUST) ||
646                     (acct_flags & ACB_SVRTRUST) ||
647                     (acct_flags & ACB_DOMTRUST) ) {
648                 add_script = talloc_strdup(mem_ctx, lp_addmachine_script());
649         } else {
650                 DEBUG(1, ("Unknown user type: %s\n",
651                           pdb_encode_acct_ctrl(acct_flags, NEW_PW_FORMAT_SPACE_PADDED_LEN)));
652                 return NT_STATUS_UNSUCCESSFUL;
653         }
654
655         if (!add_script) {
656                 return NT_STATUS_NO_MEMORY;
657         }
658
659         if (*add_script) {
660                 int add_ret;
661                 add_script = talloc_all_string_sub(mem_ctx, add_script,
662                                                    "%u", account);
663                 if (!add_script) {
664                         return NT_STATUS_NO_MEMORY;
665                 }
666                 add_ret = smbrun(add_script, NULL);
667                 DEBUG(add_ret ? 0 : 1,("fetch_account: Running the command `%s' "
668                          "gave %d\n", add_script, add_ret));
669                 if (add_ret == 0) {
670                         smb_nscd_flush_user_cache();
671                 }
672         }
673
674         /* try and find the possible unix account again */
675         passwd = Get_Pwnam_alloc(mem_ctx, account);
676         if (!passwd) {
677                 return NT_STATUS_NO_SUCH_USER;
678         }
679
680         *passwd_p = passwd;
681
682         return NT_STATUS_OK;
683 }
684
685 static struct drsuapi_DsReplicaAttribute *find_drsuapi_attr(
686                         const struct drsuapi_DsReplicaObjectListItemEx *cur,
687                         uint32_t attid)
688 {
689         int i = 0;
690
691         for (i = 0; i < cur->object.attribute_ctr.num_attributes; i++) {
692                 struct drsuapi_DsReplicaAttribute *attr;
693
694                 attr = &cur->object.attribute_ctr.attributes[i];
695
696                 if (attr->attid == attid) {
697                         return attr;
698                 }
699         }
700
701         return NULL;
702 }
703
704 static NTSTATUS find_drsuapi_attr_string(TALLOC_CTX *mem_ctx,
705                                          const struct drsuapi_DsReplicaObjectListItemEx *cur,
706                                          uint32_t attid,
707                                          uint32_t *_count,
708                                          char ***_array)
709 {
710         struct drsuapi_DsReplicaAttribute *attr;
711         char **array;
712         uint32_t a;
713
714         attr = find_drsuapi_attr(cur, attid);
715         if (attr == NULL) {
716                 return NT_STATUS_PROPSET_NOT_FOUND;
717         }
718
719         array = talloc_array(mem_ctx, char *, attr->value_ctr.num_values);
720         if (array == NULL) {
721                 return NT_STATUS_NO_MEMORY;
722         }
723
724         for (a = 0; a < attr->value_ctr.num_values; a++) {
725                 const DATA_BLOB *blob;
726                 ssize_t ret;
727
728                 blob = attr->value_ctr.values[a].blob;
729
730                 if (blob == NULL) {
731                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
732                 }
733
734                 ret = pull_string_talloc(array, NULL, 0, &array[a],
735                                          blob->data, blob->length,
736                                          STR_UNICODE);
737                 if (ret == -1) {
738                         //TODO
739                         return NT_STATUS_INTERNAL_ERROR;
740                 }
741         }
742
743         *_count = attr->value_ctr.num_values;
744         *_array = array;
745         return NT_STATUS_OK;
746 }
747
748 static NTSTATUS find_drsuapi_attr_int32(TALLOC_CTX *mem_ctx,
749                                         const struct drsuapi_DsReplicaObjectListItemEx *cur,
750                                         uint32_t attid,
751                                         uint32_t *_count,
752                                         int32_t **_array)
753 {
754         struct drsuapi_DsReplicaAttribute *attr;
755         int32_t *array;
756         uint32_t a;
757
758         attr = find_drsuapi_attr(cur, attid);
759         if (attr == NULL) {
760                 return NT_STATUS_PROPSET_NOT_FOUND;
761         }
762
763         array = talloc_array(mem_ctx, int32_t, attr->value_ctr.num_values);
764         if (array == NULL) {
765                 return NT_STATUS_NO_MEMORY;
766         }
767
768         for (a = 0; a < attr->value_ctr.num_values; a++) {
769                 const DATA_BLOB *blob;
770
771                 blob = attr->value_ctr.values[a].blob;
772
773                 if (blob == NULL) {
774                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
775                 }
776
777                 if (blob->length != 4) {
778                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
779                 }
780
781                 array[a] = IVAL(blob->data, 0);
782         }
783
784         *_count = attr->value_ctr.num_values;
785         *_array = array;
786         return NT_STATUS_OK;
787 }
788
789 static NTSTATUS find_drsuapi_attr_blob(TALLOC_CTX *mem_ctx,
790                                        const struct drsuapi_DsReplicaObjectListItemEx *cur,
791                                        uint32_t attid,
792                                        uint32_t *_count,
793                                        DATA_BLOB **_array)
794 {
795         struct drsuapi_DsReplicaAttribute *attr;
796         DATA_BLOB *array;
797         uint32_t a;
798
799         attr = find_drsuapi_attr(cur, attid);
800         if (attr == NULL) {
801                 return NT_STATUS_PROPSET_NOT_FOUND;
802         }
803
804         array = talloc_array(mem_ctx, DATA_BLOB, attr->value_ctr.num_values);
805         if (array == NULL) {
806                 return NT_STATUS_NO_MEMORY;
807         }
808
809         for (a = 0; a < attr->value_ctr.num_values; a++) {
810                 const DATA_BLOB *blob;
811
812                 blob = attr->value_ctr.values[a].blob;
813
814                 if (blob == NULL) {
815                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
816                 }
817
818                 array[a] = data_blob_talloc(array, blob->data, blob->length);
819                 if (array[a].length != blob->length) {
820                         return NT_STATUS_NO_MEMORY;
821                 }
822         }
823         *_count = attr->value_ctr.num_values;
824         *_array = array;
825         return NT_STATUS_OK;
826 }
827
828 static NTSTATUS find_drsuapi_attr_int64(TALLOC_CTX *mem_ctx,
829                                         const struct drsuapi_DsReplicaObjectListItemEx *cur,
830                                         uint32_t attid,
831                                         uint32_t *_count,
832                                         int64_t **_array)
833 {
834         struct drsuapi_DsReplicaAttribute *attr;
835         int64_t *array;
836         uint32_t a;
837
838         attr = find_drsuapi_attr(cur, attid);
839         if (attr == NULL) {
840                 return NT_STATUS_PROPSET_NOT_FOUND;
841         }
842
843         array = talloc_array(mem_ctx, int64_t, attr->value_ctr.num_values);
844         if (array == NULL) {
845                 return NT_STATUS_NO_MEMORY;
846         }
847
848         for (a = 0; a < attr->value_ctr.num_values; a++) {
849                 const DATA_BLOB *blob;
850
851                 blob = attr->value_ctr.values[a].blob;
852
853                 if (blob == NULL) {
854                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
855                 }
856
857                 if (blob->length != 8) {
858                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
859                 }
860
861                 array[a] = BVAL(blob->data, 0);
862         }
863         *_count = attr->value_ctr.num_values;
864         *_array = array;
865         return NT_STATUS_OK;
866 }
867
868 static NTSTATUS find_drsuapi_attr_dn(TALLOC_CTX *mem_ctx,
869                                      const struct drsuapi_DsReplicaObjectListItemEx *cur,
870                                      uint32_t attid,
871                                      uint32_t *_count,
872                                      struct drsuapi_DsReplicaObjectIdentifier3 **_array)
873 {
874         struct drsuapi_DsReplicaAttribute *attr;
875         struct drsuapi_DsReplicaObjectIdentifier3 *array;
876         uint32_t a;
877
878         attr = find_drsuapi_attr(cur, attid);
879         if (attr == NULL) {
880                 return NT_STATUS_PROPSET_NOT_FOUND;
881         }
882
883         array = talloc_array(mem_ctx,
884                              struct drsuapi_DsReplicaObjectIdentifier3,
885                              attr->value_ctr.num_values);
886         if (array == NULL) {
887                 return NT_STATUS_NO_MEMORY;
888         }
889
890         for (a = 0; a < attr->value_ctr.num_values; a++) {
891                 const DATA_BLOB *blob;
892                 enum ndr_err_code ndr_err;
893                 NTSTATUS status;
894
895                 blob = attr->value_ctr.values[a].blob;
896
897                 if (blob == NULL) {
898                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
899                 }
900
901                 /* windows sometimes sends an extra two pad bytes here */
902                 ndr_err = ndr_pull_struct_blob(blob, array, &array[a],
903                                 (ndr_pull_flags_fn_t)ndr_pull_drsuapi_DsReplicaObjectIdentifier3);
904                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
905                         status = ndr_map_error2ntstatus(ndr_err);
906                         return status;
907                 }
908         }
909         *_count = attr->value_ctr.num_values;
910         *_array = array;
911         return NT_STATUS_OK;
912 }
913
914 #define GET_BLOB_EX(attr, needed) do { \
915         NTSTATUS _status; \
916         uint32_t _cnt; \
917         DATA_BLOB *_vals = NULL; \
918         attr = data_blob_null; \
919         _status = find_drsuapi_attr_blob(mem_ctx, cur, \
920                                          DRSUAPI_ATTID_ ## attr, \
921                                          &_cnt, &_vals); \
922         if (NT_STATUS_EQUAL(_status, NT_STATUS_PROPSET_NOT_FOUND)) { \
923                 if (!needed) { \
924                         _status = NT_STATUS_OK; \
925                         _cnt = 0; \
926                 } \
927         } \
928         if (!NT_STATUS_IS_OK(_status)) { \
929                 DEBUG(0,(__location__ "attr[%s] %s\n", \
930                         #attr, nt_errstr(_status))); \
931                 return _status; \
932         } \
933         if (_cnt == 0) { \
934                 if (needed) { \
935                         talloc_free(_vals); \
936                         DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
937                         return NT_STATUS_OBJECT_NAME_NOT_FOUND; \
938                 } \
939         } else if (_cnt > 1) { \
940                 talloc_free(_vals); \
941                 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
942                 return NT_STATUS_INTERNAL_DB_CORRUPTION; \
943         } else { \
944                 attr = _vals[0]; \
945                 (void)talloc_steal(mem_ctx, _vals[0].data); \
946         } \
947         talloc_free(_vals); \
948 } while(0)
949
950 #define GET_STRING_EX(attr, needed) do { \
951         NTSTATUS _status; \
952         uint32_t _cnt; \
953         char **_vals = NULL; \
954         attr = NULL; \
955         _status = find_drsuapi_attr_string(mem_ctx, cur, \
956                                            DRSUAPI_ATTID_ ## attr, \
957                                            &_cnt, &_vals); \
958         if (NT_STATUS_EQUAL(_status, NT_STATUS_PROPSET_NOT_FOUND)) { \
959                 if (!needed) { \
960                         _status = NT_STATUS_OK; \
961                         _cnt = 0; \
962                 } \
963         } \
964         if (!NT_STATUS_IS_OK(_status)) { \
965                 DEBUG(0,(__location__ "attr[%s] %s\n", \
966                         #attr, nt_errstr(_status))); \
967                 return _status; \
968         } \
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; \
974                 } \
975         } else if (_cnt > 1) { \
976                 talloc_free(_vals); \
977                 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
978                 return NT_STATUS_INTERNAL_DB_CORRUPTION; \
979         } else { \
980                 attr = talloc_move(mem_ctx, &_vals[0]); \
981         } \
982         talloc_free(_vals); \
983 } while(0)
984
985 #define GET_UINT32_EX(attr, needed) do { \
986         NTSTATUS _status; \
987         uint32_t _cnt; \
988         int32_t*_vals = NULL; \
989         attr = 0; \
990         _status = find_drsuapi_attr_int32(mem_ctx, cur, \
991                                           DRSUAPI_ATTID_ ## attr, \
992                                           &_cnt, &_vals); \
993         if (NT_STATUS_EQUAL(_status, NT_STATUS_PROPSET_NOT_FOUND)) { \
994                 if (!needed) { \
995                         _status = NT_STATUS_OK; \
996                         _cnt = 0; \
997                 } \
998         } \
999         if (!NT_STATUS_IS_OK(_status)) { \
1000                 DEBUG(0,(__location__ "attr[%s] %s\n", \
1001                         #attr, nt_errstr(_status))); \
1002                 return _status; \
1003         } \
1004         if (_cnt == 0) { \
1005                 if (needed) { \
1006                         talloc_free(_vals); \
1007                         DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1008                         return NT_STATUS_OBJECT_NAME_NOT_FOUND; \
1009                 } \
1010         } else if (_cnt > 1) { \
1011                 talloc_free(_vals); \
1012                 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1013                 return NT_STATUS_INTERNAL_DB_CORRUPTION; \
1014         } else { \
1015                 attr = (uint32_t)_vals[0]; \
1016         } \
1017         talloc_free(_vals); \
1018 } while(0)
1019
1020 #define GET_UINT64_EX(attr, needed) do { \
1021         NTSTATUS _status; \
1022         uint32_t _cnt; \
1023         int64_t *_vals = NULL; \
1024         attr = 0; \
1025         _status = find_drsuapi_attr_int64(mem_ctx, cur, \
1026                                           DRSUAPI_ATTID_ ## attr, \
1027                                           &_cnt, &_vals); \
1028         if (NT_STATUS_EQUAL(_status, NT_STATUS_PROPSET_NOT_FOUND)) { \
1029                 if (!needed) { \
1030                         _status = NT_STATUS_OK; \
1031                         _cnt = 0; \
1032                 } \
1033         } \
1034         if (!NT_STATUS_IS_OK(_status)) { \
1035                 DEBUG(0,(__location__ "attr[%s] %s\n", \
1036                         #attr, nt_errstr(_status))); \
1037                 return _status; \
1038         } \
1039         if (_cnt == 0) { \
1040                 if (needed) { \
1041                         talloc_free(_vals); \
1042                         DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1043                         return NT_STATUS_OBJECT_NAME_NOT_FOUND; \
1044                 } \
1045         } else if (_cnt > 1) { \
1046                 talloc_free(_vals); \
1047                 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1048                 return NT_STATUS_INTERNAL_DB_CORRUPTION; \
1049         } else { \
1050                 attr = (uint64_t)_vals[0]; \
1051         } \
1052         talloc_free(_vals); \
1053 } while(0)
1054
1055 #define GET_BLOB(attr) GET_BLOB_EX(attr, false)
1056 #define GET_STRING(attr) GET_STRING_EX(attr, false)
1057 #define GET_UINT32(attr) GET_UINT32_EX(attr, false)
1058 #define GET_UINT64(attr) GET_UINT64_EX(attr, false)
1059
1060 /* Convert a struct samu_DELTA to a struct samu. */
1061 #define STRING_CHANGED (old_string && !new_string) ||\
1062                     (!old_string && new_string) ||\
1063                 (old_string && new_string && (strcmp(old_string, new_string) != 0))
1064
1065 #define STRING_CHANGED_NC(s1,s2) ((s1) && !(s2)) ||\
1066                     (!(s1) && (s2)) ||\
1067                 ((s1) && (s2) && (strcmp((s1), (s2)) != 0))
1068
1069 /****************************************************************
1070 ****************************************************************/
1071
1072 static NTSTATUS sam_account_from_object(struct samu *account,
1073                                 struct drsuapi_DsReplicaObjectListItemEx *cur)
1074 {
1075         TALLOC_CTX *mem_ctx = account;
1076         const char *old_string, *new_string;
1077         time_t unix_time, stored_time;
1078         uchar zero_buf[16];
1079         NTSTATUS status;
1080
1081         NTTIME lastLogon;
1082         NTTIME lastLogoff;
1083         NTTIME pwdLastSet;
1084         NTTIME accountExpires;
1085         const char *sAMAccountName;
1086         const char *displayName;
1087         const char *homeDirectory;
1088         const char *homeDrive;
1089         const char *scriptPath;
1090         const char *profilePath;
1091         const char *description;
1092         const char *userWorkstations;
1093         const char *comment;
1094         DATA_BLOB userParameters;
1095         struct dom_sid objectSid;
1096         uint32_t primaryGroupID;
1097         uint32_t userAccountControl;
1098         DATA_BLOB logonHours;
1099         uint32_t badPwdCount;
1100         uint32_t logonCount;
1101         DATA_BLOB unicodePwd;
1102         DATA_BLOB dBCSPwd;
1103
1104         uint32_t rid = 0;
1105         uint32_t acct_flags;
1106         uint32_t units_per_week;
1107
1108         memset(zero_buf, '\0', sizeof(zero_buf));
1109
1110         objectSid = cur->object.identifier->sid;
1111         GET_STRING_EX(sAMAccountName, true);
1112         DEBUG(0,("sam_account_from_object(%s, %s) start\n",
1113                  sAMAccountName, sid_string_dbg(&objectSid)));
1114         GET_UINT64(lastLogon);
1115         GET_UINT64(lastLogoff);
1116         GET_UINT64(pwdLastSet);
1117         GET_UINT64(accountExpires);
1118         GET_STRING(displayName);
1119         GET_STRING(homeDirectory);
1120         GET_STRING(homeDrive);
1121         GET_STRING(scriptPath);
1122         GET_STRING(profilePath);
1123         GET_STRING(description);
1124         GET_STRING(userWorkstations);
1125         GET_STRING(comment);
1126         GET_BLOB(userParameters);
1127         GET_UINT32(primaryGroupID);
1128         GET_UINT32(userAccountControl);
1129         GET_BLOB(logonHours);
1130         GET_UINT32(badPwdCount);
1131         GET_UINT32(logonCount);
1132         GET_BLOB(unicodePwd);
1133         GET_BLOB(dBCSPwd);
1134
1135         status = dom_sid_split_rid(mem_ctx, &objectSid, NULL, &rid);
1136         if (!NT_STATUS_IS_OK(status)) {
1137                 return status;
1138         }
1139         acct_flags = ds_uf2acb(userAccountControl);
1140
1141         /* Username, fullname, home dir, dir drive, logon script, acct
1142            desc, workstations, profile. */
1143
1144         if (sAMAccountName) {
1145                 old_string = pdb_get_nt_username(account);
1146                 new_string = sAMAccountName;
1147
1148                 if (STRING_CHANGED) {
1149                         pdb_set_nt_username(account, new_string, PDB_CHANGED);
1150                 }
1151
1152                 /* Unix username is the same - for sanity */
1153                 old_string = pdb_get_username( account );
1154                 if (STRING_CHANGED) {
1155                         pdb_set_username(account, new_string, PDB_CHANGED);
1156                 }
1157         }
1158
1159         if (displayName) {
1160                 old_string = pdb_get_fullname(account);
1161                 new_string = displayName;
1162
1163                 if (STRING_CHANGED)
1164                         pdb_set_fullname(account, new_string, PDB_CHANGED);
1165         }
1166
1167         if (homeDirectory) {
1168                 old_string = pdb_get_homedir(account);
1169                 new_string = homeDirectory;
1170
1171                 if (STRING_CHANGED)
1172                         pdb_set_homedir(account, new_string, PDB_CHANGED);
1173         }
1174
1175         if (homeDrive) {
1176                 old_string = pdb_get_dir_drive(account);
1177                 new_string = homeDrive;
1178
1179                 if (STRING_CHANGED)
1180                         pdb_set_dir_drive(account, new_string, PDB_CHANGED);
1181         }
1182
1183         if (scriptPath) {
1184                 old_string = pdb_get_logon_script(account);
1185                 new_string = scriptPath;
1186
1187                 if (STRING_CHANGED)
1188                         pdb_set_logon_script(account, new_string, PDB_CHANGED);
1189         }
1190
1191         if (description) {
1192                 old_string = pdb_get_acct_desc(account);
1193                 new_string = description;
1194
1195                 if (STRING_CHANGED)
1196                         pdb_set_acct_desc(account, new_string, PDB_CHANGED);
1197         }
1198
1199         if (userWorkstations) {
1200                 old_string = pdb_get_workstations(account);
1201                 new_string = userWorkstations;
1202
1203                 if (STRING_CHANGED)
1204                         pdb_set_workstations(account, new_string, PDB_CHANGED);
1205         }
1206
1207         if (profilePath) {
1208                 old_string = pdb_get_profile_path(account);
1209                 new_string = profilePath;
1210
1211                 if (STRING_CHANGED)
1212                         pdb_set_profile_path(account, new_string, PDB_CHANGED);
1213         }
1214
1215         if (userParameters.data) {
1216                 char *newstr;
1217                 old_string = pdb_get_munged_dial(account);
1218                 newstr = (userParameters.length == 0) ? NULL :
1219                         base64_encode_data_blob(talloc_tos(), userParameters);
1220
1221                 if (STRING_CHANGED_NC(old_string, newstr))
1222                         pdb_set_munged_dial(account, newstr, PDB_CHANGED);
1223                 TALLOC_FREE(newstr);
1224         }
1225
1226         /* User and group sid */
1227         if (rid != 0 && pdb_get_user_rid(account) != rid) {
1228                 pdb_set_user_sid_from_rid(account, rid, PDB_CHANGED);
1229         }
1230         if (primaryGroupID != 0 && pdb_get_group_rid(account) != primaryGroupID) {
1231                 pdb_set_group_sid_from_rid(account, primaryGroupID, PDB_CHANGED);
1232         }
1233
1234         /* Logon and password information */
1235         if (!nt_time_is_zero(&lastLogon)) {
1236                 unix_time = nt_time_to_unix(lastLogon);
1237                 stored_time = pdb_get_logon_time(account);
1238                 if (stored_time != unix_time)
1239                         pdb_set_logon_time(account, unix_time, PDB_CHANGED);
1240         }
1241
1242         if (!nt_time_is_zero(&lastLogoff)) {
1243                 unix_time = nt_time_to_unix(lastLogoff);
1244                 stored_time = pdb_get_logoff_time(account);
1245                 if (stored_time != unix_time)
1246                         pdb_set_logoff_time(account, unix_time,PDB_CHANGED);
1247         }
1248
1249         /* Logon Divs */
1250         units_per_week = logonHours.length * 8;
1251
1252         if (pdb_get_logon_divs(account) != units_per_week) {
1253                 pdb_set_logon_divs(account, units_per_week, PDB_CHANGED);
1254         }
1255
1256         /* Logon Hours Len */
1257         if (units_per_week/8 != pdb_get_hours_len(account)) {
1258                 pdb_set_hours_len(account, units_per_week/8, PDB_CHANGED);
1259         }
1260
1261         /* Logon Hours */
1262         if (logonHours.data) {
1263                 char oldstr[44], newstr[44];
1264                 pdb_sethexhours(oldstr, pdb_get_hours(account));
1265                 pdb_sethexhours(newstr, logonHours.data);
1266                 if (!strequal(oldstr, newstr)) {
1267                         pdb_set_hours(account, logonHours.data,
1268                                       logonHours.length, PDB_CHANGED);
1269                 }
1270         }
1271
1272         if (pdb_get_bad_password_count(account) != badPwdCount)
1273                 pdb_set_bad_password_count(account, badPwdCount, PDB_CHANGED);
1274
1275         if (pdb_get_logon_count(account) != logonCount)
1276                 pdb_set_logon_count(account, logonCount, PDB_CHANGED);
1277
1278         if (!nt_time_is_zero(&pwdLastSet)) {
1279                 unix_time = nt_time_to_unix(pwdLastSet);
1280                 stored_time = pdb_get_pass_last_set_time(account);
1281                 if (stored_time != unix_time)
1282                         pdb_set_pass_last_set_time(account, unix_time, PDB_CHANGED);
1283         } else {
1284                 /* no last set time, make it now */
1285                 pdb_set_pass_last_set_time(account, time(NULL), PDB_CHANGED);
1286         }
1287
1288         if (!nt_time_is_zero(&accountExpires)) {
1289                 unix_time = nt_time_to_unix(accountExpires);
1290                 stored_time = pdb_get_kickoff_time(account);
1291                 if (stored_time != unix_time)
1292                         pdb_set_kickoff_time(account, unix_time, PDB_CHANGED);
1293         }
1294
1295         /* Decode hashes from password hash
1296            Note that win2000 may send us all zeros for the hashes if it doesn't
1297            think this channel is secure enough - don't set the passwords at all
1298            in that case
1299         */
1300         if (dBCSPwd.length == 16 && memcmp(dBCSPwd.data, zero_buf, 16) != 0) {
1301                 pdb_set_lanman_passwd(account, dBCSPwd.data, PDB_CHANGED);
1302         }
1303
1304         if (unicodePwd.length == 16 && memcmp(unicodePwd.data, zero_buf, 16) != 0) {
1305                 pdb_set_nt_passwd(account, unicodePwd.data, PDB_CHANGED);
1306         }
1307
1308         /* TODO: history */
1309
1310         /* TODO: account expiry time */
1311
1312         pdb_set_acct_ctrl(account, acct_flags, PDB_CHANGED);
1313
1314         pdb_set_domain(account, lp_workgroup(), PDB_CHANGED);
1315
1316         DEBUG(0,("sam_account_from_object(%s, %s) done\n",
1317                  sAMAccountName, sid_string_dbg(&objectSid)));
1318         return NT_STATUS_OK;
1319 }
1320
1321 /****************************************************************
1322 ****************************************************************/
1323
1324 static NTSTATUS handle_account_object(struct dssync_passdb *pctx,
1325                                       TALLOC_CTX *mem_ctx,
1326                                       struct dssync_passdb_obj *obj)
1327 {
1328         struct drsuapi_DsReplicaObjectListItemEx *cur = obj->cur;
1329         NTSTATUS status;
1330         fstring account;
1331         struct samu *sam_account=NULL;
1332         GROUP_MAP map;
1333         struct group *grp;
1334         struct dom_sid user_sid;
1335         struct dom_sid group_sid;
1336         struct passwd *passwd = NULL;
1337         uint32_t acct_flags;
1338         uint32_t rid;
1339
1340         const char *sAMAccountName;
1341         uint32_t sAMAccountType;
1342         uint32_t userAccountControl;
1343
1344         user_sid = cur->object.identifier->sid;
1345         GET_STRING_EX(sAMAccountName, true);
1346         GET_UINT32_EX(sAMAccountType, true);
1347         GET_UINT32_EX(userAccountControl, true);
1348
1349         status = dom_sid_split_rid(mem_ctx, &user_sid, NULL, &rid);
1350         if (!NT_STATUS_IS_OK(status)) {
1351                 return status;
1352         }
1353
1354         fstrcpy(account, sAMAccountName);
1355         if (rid == DOMAIN_RID_GUEST) {
1356                 /*
1357                  * pdb_getsampwsid() has special handling for DOMAIN_RID_GUEST
1358                  * that's why we need to ignore it here.
1359                  *
1360                  * pdb_smbpasswd.c also has some DOMAIN_RID_GUEST related
1361                  * code...
1362                  */
1363                 DEBUG(0,("Ignore %s - %s\n", account, sid_string_dbg(&user_sid)));
1364                 return NT_STATUS_OK;
1365         }
1366         DEBUG(0,("Creating account: %s\n", account));
1367
1368         if ( !(sam_account = samu_new(mem_ctx)) ) {
1369                 return NT_STATUS_NO_MEMORY;
1370         }
1371
1372         acct_flags = ds_uf2acb(userAccountControl);
1373         status = smb_create_user(sam_account, acct_flags, account, &passwd);
1374         if (!NT_STATUS_IS_OK(status)) {
1375                 DEBUG(0,("Could not create posix account info for '%s'- %s\n",
1376                         account, nt_errstr(status)));
1377                 TALLOC_FREE(sam_account);
1378                 return status;
1379         }
1380
1381         DEBUG(3, ("Attempting to find SID %s for user %s in the passdb\n",
1382                   sid_string_dbg(&user_sid), account));
1383         if (!pdb_getsampwsid(sam_account, &user_sid)) {
1384                 sam_account_from_object(sam_account, cur);
1385                 DEBUG(3, ("Attempting to add user SID %s for user %s in the passdb\n",
1386                           sid_string_dbg(&user_sid),
1387                           pdb_get_username(sam_account)));
1388                 if (!NT_STATUS_IS_OK(pdb_add_sam_account(sam_account))) {
1389                         DEBUG(1, ("SAM Account for %s failed to be added to the passdb!\n",
1390                                   account));
1391                         TALLOC_FREE(sam_account);
1392                         return NT_STATUS_ACCESS_DENIED;
1393                 }
1394         } else {
1395                 sam_account_from_object(sam_account, cur);
1396                 DEBUG(3, ("Attempting to update user SID %s for user %s in the passdb\n",
1397                           sid_string_dbg(&user_sid),
1398                           pdb_get_username(sam_account)));
1399                 if (!NT_STATUS_IS_OK(pdb_update_sam_account(sam_account))) {
1400                         DEBUG(1, ("SAM Account for %s failed to be updated in the passdb!\n",
1401                                   account));
1402                         TALLOC_FREE(sam_account);
1403                         return NT_STATUS_ACCESS_DENIED;
1404                 }
1405         }
1406
1407         if (pdb_get_group_sid(sam_account) == NULL) {
1408                 TALLOC_FREE(sam_account);
1409                 return NT_STATUS_UNSUCCESSFUL;
1410         }
1411
1412         group_sid = *pdb_get_group_sid(sam_account);
1413
1414         if (!pdb_getgrsid(&map, group_sid)) {
1415                 DEBUG(0, ("Primary group of %s has no mapping!\n",
1416                           pdb_get_username(sam_account)));
1417         } else {
1418                 if (map.gid != passwd->pw_gid) {
1419                         if (!(grp = getgrgid(map.gid))) {
1420                                 DEBUG(0, ("Could not find unix group %lu for user %s (group SID=%s)\n",
1421                                           (unsigned long)map.gid, pdb_get_username(sam_account),
1422                                           sid_string_dbg(&group_sid)));
1423                         } else {
1424                                 smb_set_primary_group(grp->gr_name, pdb_get_username(sam_account));
1425                         }
1426                 }
1427         }
1428
1429         if ( !passwd ) {
1430                 DEBUG(1, ("No unix user for this account (%s), cannot adjust mappings\n",
1431                         pdb_get_username(sam_account)));
1432         }
1433
1434         TALLOC_FREE(sam_account);
1435         return NT_STATUS_OK;
1436 }
1437
1438 /****************************************************************
1439 ****************************************************************/
1440
1441 static NTSTATUS handle_alias_object(struct dssync_passdb *pctx,
1442                                     TALLOC_CTX *mem_ctx,
1443                                     struct dssync_passdb_obj *obj)
1444 {
1445         struct drsuapi_DsReplicaObjectListItemEx *cur = obj->cur;
1446         NTSTATUS status;
1447         fstring name;
1448         fstring comment;
1449         struct group *grp = NULL;
1450         struct dom_sid group_sid;
1451         uint32_t rid = 0;
1452         struct dom_sid *dom_sid = NULL;
1453         fstring sid_string;
1454         GROUP_MAP map;
1455         bool insert = true;
1456
1457         const char *sAMAccountName;
1458         uint32_t sAMAccountType;
1459         uint32_t groupType;
1460         const char *description;
1461         uint32_t i;
1462         uint32_t num_members = 0;
1463         struct drsuapi_DsReplicaObjectIdentifier3 *members = NULL;
1464
1465         group_sid = cur->object.identifier->sid;
1466         GET_STRING_EX(sAMAccountName, true);
1467         GET_UINT32_EX(sAMAccountType, true);
1468         GET_UINT32_EX(groupType, true);
1469         GET_STRING(description);
1470
1471         status = find_drsuapi_attr_dn(obj, cur, DRSUAPI_ATTID_member,
1472                                       &num_members, &members);
1473         if (NT_STATUS_EQUAL(status, NT_STATUS_PROPSET_NOT_FOUND)) {
1474                 status = NT_STATUS_OK;
1475         }
1476         if (!NT_STATUS_IS_OK(status)) {
1477                 return status;
1478         }
1479
1480         fstrcpy(name, sAMAccountName);
1481         fstrcpy(comment, description);
1482
1483         dom_sid_split_rid(mem_ctx, &group_sid, &dom_sid, &rid);
1484
1485         sid_to_fstring(sid_string, &group_sid);
1486         DEBUG(0,("Creating alias[%s] - %s members[%u]\n",
1487                   name, sid_string, num_members));
1488
1489         status = dssync_insert_obj(pctx, pctx->aliases, obj);
1490         if (!NT_STATUS_IS_OK(status)) {
1491                 return status;
1492         }
1493
1494         if (pdb_getgrsid(&map, group_sid)) {
1495                 if ( map.gid != -1 )
1496                         grp = getgrgid(map.gid);
1497                 insert = false;
1498         }
1499
1500         if (grp == NULL) {
1501                 gid_t gid;
1502
1503                 /* No group found from mapping, find it from its name. */
1504                 if ((grp = getgrnam(name)) == NULL) {
1505
1506                         /* No appropriate group found, create one */
1507
1508                         DEBUG(0,("Creating unix group: '%s'\n", name));
1509
1510                         if (smb_create_group(name, &gid) != 0)
1511                                 return NT_STATUS_ACCESS_DENIED;
1512
1513                         if ((grp = getgrgid(gid)) == NULL)
1514                                 return NT_STATUS_ACCESS_DENIED;
1515                 }
1516         }
1517
1518         map.gid = grp->gr_gid;
1519         map.sid = group_sid;
1520
1521         if (dom_sid_equal(dom_sid, &global_sid_Builtin)) {
1522                 /*
1523                  * pdb_ldap does not like SID_NAME_WKN_GRP...
1524                  *
1525                  * map.sid_name_use = SID_NAME_WKN_GRP;
1526                  */
1527                 map.sid_name_use = SID_NAME_ALIAS;
1528         } else {
1529                 map.sid_name_use = SID_NAME_ALIAS;
1530         }
1531
1532         fstrcpy(map.nt_name, name);
1533         if (description) {
1534                 fstrcpy(map.comment, comment);
1535         } else {
1536                 fstrcpy(map.comment, "");
1537         }
1538
1539         if (insert)
1540                 pdb_add_group_mapping_entry(&map);
1541         else
1542                 pdb_update_group_mapping_entry(&map);
1543
1544         for (i=0; i < num_members; i++) {
1545                 struct dssync_passdb_mem *mem;
1546
1547                 status = dssync_create_mem(pctx, obj,
1548                                            true /* active */,
1549                                            &members[i], &mem);
1550                 if (!NT_STATUS_IS_OK(status)) {
1551                         return status;
1552                 }
1553         }
1554
1555         return NT_STATUS_OK;
1556 }
1557
1558 /****************************************************************
1559 ****************************************************************/
1560
1561 static NTSTATUS handle_group_object(struct dssync_passdb *pctx,
1562                                     TALLOC_CTX *mem_ctx,
1563                                     struct dssync_passdb_obj *obj)
1564 {
1565         struct drsuapi_DsReplicaObjectListItemEx *cur = obj->cur;
1566         NTSTATUS status;
1567         fstring name;
1568         fstring comment;
1569         struct group *grp = NULL;
1570         struct dom_sid group_sid;
1571         fstring sid_string;
1572         GROUP_MAP map;
1573         bool insert = true;
1574
1575         const char *sAMAccountName;
1576         uint32_t sAMAccountType;
1577         uint32_t groupType;
1578         const char *description;
1579         uint32_t i;
1580         uint32_t num_members = 0;
1581         struct drsuapi_DsReplicaObjectIdentifier3 *members = NULL;
1582
1583         group_sid = cur->object.identifier->sid;
1584         GET_STRING_EX(sAMAccountName, true);
1585         GET_UINT32_EX(sAMAccountType, true);
1586         GET_UINT32_EX(groupType, true);
1587         GET_STRING(description);
1588
1589         status = find_drsuapi_attr_dn(obj, cur, DRSUAPI_ATTID_member,
1590                                       &num_members, &members);
1591         if (NT_STATUS_EQUAL(status, NT_STATUS_PROPSET_NOT_FOUND)) {
1592                 status = NT_STATUS_OK;
1593         }
1594         if (!NT_STATUS_IS_OK(status)) {
1595                 return status;
1596         }
1597
1598         fstrcpy(name, sAMAccountName);
1599         fstrcpy(comment, description);
1600
1601         sid_to_fstring(sid_string, &group_sid);
1602         DEBUG(0,("Creating group[%s] - %s members [%u]\n",
1603                   name, sid_string, num_members));
1604
1605         status = dssync_insert_obj(pctx, pctx->groups, obj);
1606         if (!NT_STATUS_IS_OK(status)) {
1607                 return status;
1608         }
1609
1610         if (pdb_getgrsid(&map, group_sid)) {
1611                 if ( map.gid != -1 )
1612                         grp = getgrgid(map.gid);
1613                 insert = false;
1614         }
1615
1616         if (grp == NULL) {
1617                 gid_t gid;
1618
1619                 /* No group found from mapping, find it from its name. */
1620                 if ((grp = getgrnam(name)) == NULL) {
1621
1622                         /* No appropriate group found, create one */
1623
1624                         DEBUG(0,("Creating unix group: '%s'\n", name));
1625
1626                         if (smb_create_group(name, &gid) != 0)
1627                                 return NT_STATUS_ACCESS_DENIED;
1628
1629                         if ((grp = getgrnam(name)) == NULL)
1630                                 return NT_STATUS_ACCESS_DENIED;
1631                 }
1632         }
1633
1634         map.gid = grp->gr_gid;
1635         map.sid = group_sid;
1636         map.sid_name_use = SID_NAME_DOM_GRP;
1637         fstrcpy(map.nt_name, name);
1638         if (description) {
1639                 fstrcpy(map.comment, comment);
1640         } else {
1641                 fstrcpy(map.comment, "");
1642         }
1643
1644         if (insert)
1645                 pdb_add_group_mapping_entry(&map);
1646         else
1647                 pdb_update_group_mapping_entry(&map);
1648
1649         for (i=0; i < num_members; i++) {
1650                 struct dssync_passdb_mem *mem;
1651
1652                 status = dssync_create_mem(pctx, obj,
1653                                            true /* active */,
1654                                            &members[i], &mem);
1655                 if (!NT_STATUS_IS_OK(status)) {
1656                         return status;
1657                 }
1658         }
1659
1660         return NT_STATUS_OK;
1661 }
1662
1663 /****************************************************************
1664 ****************************************************************/
1665
1666 static NTSTATUS handle_interdomain_trust_object(struct dssync_passdb *pctx,
1667                                                 TALLOC_CTX *mem_ctx,
1668                                                 struct dssync_passdb_obj *obj)
1669 {
1670         struct drsuapi_DsReplicaObjectListItemEx *cur = obj->cur;
1671         DEBUG(0,("trust: %s\n", cur->object.identifier->dn));
1672         return NT_STATUS_NOT_IMPLEMENTED;
1673 }
1674
1675 /****************************************************************
1676 ****************************************************************/
1677
1678 struct dssync_object_table_t {
1679         uint32_t type;
1680         NTSTATUS (*fn) (struct dssync_passdb *pctx,
1681                         TALLOC_CTX *mem_ctx,
1682                         struct dssync_passdb_obj *obj);
1683 };
1684
1685 static const struct dssync_object_table_t dssync_object_table[] = {
1686         { ATYPE_NORMAL_ACCOUNT,         handle_account_object },
1687         { ATYPE_WORKSTATION_TRUST,      handle_account_object },
1688         { ATYPE_SECURITY_LOCAL_GROUP,   handle_alias_object },
1689         { ATYPE_SECURITY_GLOBAL_GROUP,  handle_group_object },
1690         { ATYPE_INTERDOMAIN_TRUST,      handle_interdomain_trust_object },
1691 };
1692
1693 /****************************************************************
1694 ****************************************************************/
1695
1696 static NTSTATUS parse_object(struct dssync_passdb *pctx,
1697                              TALLOC_CTX *mem_ctx,
1698                              struct drsuapi_DsReplicaObjectListItemEx *cur)
1699 {
1700         NTSTATUS status = NT_STATUS_OK;
1701         DATA_BLOB *blob;
1702         int i = 0;
1703         int a = 0;
1704         struct drsuapi_DsReplicaAttribute *attr;
1705
1706         char *name = NULL;
1707         uint32_t uacc = 0;
1708         uint32_t sam_type = 0;
1709
1710         DEBUG(3, ("parsing object '%s'\n", cur->object.identifier->dn));
1711
1712         for (i=0; i < cur->object.attribute_ctr.num_attributes; i++) {
1713
1714                 attr = &cur->object.attribute_ctr.attributes[i];
1715
1716                 if (attr->value_ctr.num_values != 1) {
1717                         continue;
1718                 }
1719
1720                 if (!attr->value_ctr.values[0].blob) {
1721                         continue;
1722                 }
1723
1724                 blob = attr->value_ctr.values[0].blob;
1725
1726                 switch (attr->attid) {
1727                         case DRSUAPI_ATTID_sAMAccountName:
1728                                 pull_string_talloc(mem_ctx, NULL, 0, &name,
1729                                                    blob->data, blob->length,
1730                                                    STR_UNICODE);
1731                                 break;
1732                         case DRSUAPI_ATTID_sAMAccountType:
1733                                 sam_type = IVAL(blob->data, 0);
1734                                 break;
1735                         case DRSUAPI_ATTID_userAccountControl:
1736                                 uacc = IVAL(blob->data, 0);
1737                                 break;
1738                         default:
1739                                 break;
1740                 }
1741         }
1742
1743         for (a=0; a < ARRAY_SIZE(dssync_object_table); a++) {
1744                 if (sam_type == dssync_object_table[a].type) {
1745                         if (dssync_object_table[a].fn) {
1746                                 struct dssync_passdb_obj *obj;
1747                                 status = dssync_create_obj(pctx, pctx->all,
1748                                                            sam_type, cur, &obj);
1749                                 if (!NT_STATUS_IS_OK(status)) {
1750                                         break;
1751                                 }
1752                                 status = dssync_object_table[a].fn(pctx,
1753                                                                    mem_ctx,
1754                                                                    obj);
1755                                 break;
1756                         }
1757                 }
1758         }
1759
1760         return status;
1761 }
1762
1763 static NTSTATUS parse_link(struct dssync_passdb *pctx,
1764                            TALLOC_CTX *mem_ctx,
1765                            struct drsuapi_DsReplicaLinkedAttribute *cur)
1766 {
1767         struct drsuapi_DsReplicaObjectIdentifier3 *id3;
1768         const DATA_BLOB *blob;
1769         enum ndr_err_code ndr_err;
1770         NTSTATUS status;
1771         bool active = false;
1772         struct dssync_passdb_mem *mem;
1773         struct dssync_passdb_obj *obj;
1774
1775         if (cur->attid != DRSUAPI_ATTID_member) {
1776                 return NT_STATUS_OK;
1777         }
1778
1779         if (cur->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE) {
1780                 active = true;
1781         }
1782
1783         DEBUG(3, ("parsing link '%s' - %s\n",
1784                   cur->identifier->dn, active?"adding":"deleting"));
1785
1786         blob = cur->value.blob;
1787
1788         if (blob == NULL) {
1789                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1790         }
1791
1792         obj = dssync_search_obj_by_guid(pctx, pctx->all, &cur->identifier->guid);
1793         if (obj == NULL) {
1794                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1795         }
1796
1797         id3 = talloc_zero(obj, struct drsuapi_DsReplicaObjectIdentifier3);
1798         if (id3 == NULL) {
1799                 return NT_STATUS_NO_MEMORY;
1800         }
1801
1802         /* windows sometimes sends an extra two pad bytes here */
1803         ndr_err = ndr_pull_struct_blob(blob, id3, id3,
1804                         (ndr_pull_flags_fn_t)ndr_pull_drsuapi_DsReplicaObjectIdentifier3);
1805         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1806                 status = ndr_map_error2ntstatus(ndr_err);
1807                 return status;
1808         }
1809
1810         status = dssync_create_mem(pctx, obj,
1811                                    active,
1812                                    id3, &mem);
1813         if (!NT_STATUS_IS_OK(status)) {
1814                 return status;
1815         }
1816
1817         return NT_STATUS_OK;
1818 }
1819
1820 /****************************************************************
1821 ****************************************************************/
1822
1823 static NTSTATUS passdb_process_objects(struct dssync_context *ctx,
1824                                        TALLOC_CTX *mem_ctx,
1825                                        struct drsuapi_DsReplicaObjectListItemEx *cur,
1826                                        struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr)
1827 {
1828         NTSTATUS status = NT_STATUS_OK;
1829         struct dssync_passdb *pctx =
1830                 talloc_get_type_abort(ctx->private_data,
1831                 struct dssync_passdb);
1832
1833         for (; cur; cur = cur->next_object) {
1834                 status = parse_object(pctx, mem_ctx, cur);
1835                 if (!NT_STATUS_IS_OK(status)) {
1836                         goto out;
1837                 }
1838         }
1839
1840  out:
1841         return status;
1842 }
1843
1844 /****************************************************************
1845 ****************************************************************/
1846
1847 static NTSTATUS passdb_process_links(struct dssync_context *ctx,
1848                                      TALLOC_CTX *mem_ctx,
1849                                      uint32_t count,
1850                                      struct drsuapi_DsReplicaLinkedAttribute *links,
1851                                      struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr)
1852 {
1853         NTSTATUS status = NT_STATUS_OK;
1854         struct dssync_passdb *pctx =
1855                 talloc_get_type_abort(ctx->private_data,
1856                 struct dssync_passdb);
1857         uint32_t i;
1858
1859         for (i = 0; i < count; i++) {
1860                 status = parse_link(pctx, mem_ctx, &links[i]);
1861                 if (!NT_STATUS_IS_OK(status)) {
1862                         goto out;
1863                 }
1864         }
1865
1866  out:
1867         return status;
1868 }
1869
1870 /****************************************************************
1871 ****************************************************************/
1872
1873 const struct dssync_ops libnet_dssync_passdb_ops = {
1874         .startup                = passdb_startup,
1875         .process_objects        = passdb_process_objects,
1876         .process_links          = passdb_process_links,
1877         .finish                 = passdb_finish,
1878 };