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