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