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