2634552127740a568b52beaffd93594d3a0c63d4
[samba.git] / source3 / groupdb / mapping_tdb.c
1 /* 
2  *  Unix SMB/CIFS implementation.
3  *  RPC Pipe client / server routines
4  *  Copyright (C) Andrew Tridgell              1992-2006,
5  *  Copyright (C) Jean François Micouleau      1998-2001.
6  *  Copyright (C) Volker Lendecke              2006.
7  *  Copyright (C) Gerald Carter                2006.
8  *  
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 3 of the License, or
12  *  (at your option) any later version.
13  *  
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *  
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
21  */
22
23 #include "includes.h"
24 #include "system/filesys.h"
25 #include "groupdb/mapping.h"
26 #include "dbwrap.h"
27 #include "../libcli/security/security.h"
28
29 static struct db_context *db; /* used for driver files */
30
31 static bool enum_group_mapping(const struct dom_sid *domsid,
32                                enum lsa_SidType sid_name_use,
33                                GROUP_MAP **pp_rmap,
34                                size_t *p_num_entries,
35                                bool unix_only);
36 static bool group_map_remove(const struct dom_sid *sid);
37
38 static bool mapping_switch(const char *ldb_path);
39
40 /****************************************************************************
41  Open the group mapping tdb.
42 ****************************************************************************/
43 static bool init_group_mapping(void)
44 {
45         const char *ldb_path;
46
47         if (db != NULL) {
48                 return true;
49         }
50
51         db = db_open(NULL, state_path("group_mapping.tdb"), 0,
52                            TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
53         if (db == NULL) {
54                 DEBUG(0, ("Failed to open group mapping database: %s\n",
55                           strerror(errno)));
56                 return false;
57         }
58
59         ldb_path = state_path("group_mapping.ldb");
60         if (file_exist(ldb_path) && !mapping_switch(ldb_path)) {
61                 unlink(state_path("group_mapping.tdb"));
62                 return false;
63
64         } else {
65                 /* handle upgrade from old versions of the database */
66 #if 0 /* -- Needs conversion to dbwrap -- */
67                 const char *vstring = "INFO/version";
68                 int32 vers_id;
69                 GROUP_MAP *map_table = NULL;
70                 size_t num_entries = 0;
71
72                 /* handle a Samba upgrade */
73                 tdb_lock_bystring(tdb, vstring);
74
75                 /* Cope with byte-reversed older versions of the db. */
76                 vers_id = tdb_fetch_int32(tdb, vstring);
77                 if ((vers_id == DATABASE_VERSION_V1)
78                     || (IREV(vers_id) == DATABASE_VERSION_V1)) {
79                         /*
80                          * Written on a bigendian machine with old fetch_int
81                          * code. Save as le.
82                          */
83                         tdb_store_int32(tdb, vstring, DATABASE_VERSION_V2);
84                         vers_id = DATABASE_VERSION_V2;
85                 }
86
87                 /* if its an unknown version we remove everthing in the db */
88
89                 if (vers_id != DATABASE_VERSION_V2) {
90                         tdb_wipe_all(tdb);
91                         tdb_store_int32(tdb, vstring, DATABASE_VERSION_V2);
92                 }
93
94                 tdb_unlock_bystring(tdb, vstring);
95
96                 /* cleanup any map entries with a gid == -1 */
97
98                 if ( enum_group_mapping( NULL, SID_NAME_UNKNOWN, &map_table,
99                                          &num_entries, False ) ) {
100                         int i;
101
102                         for ( i=0; i<num_entries; i++ ) {
103                                 if ( map_table[i].gid == -1 ) {
104                                         group_map_remove( &map_table[i].sid );
105                                 }
106                         }
107
108                         SAFE_FREE( map_table );
109                 }
110 #endif
111         }
112         return true;
113 }
114
115 static char *group_mapping_key(TALLOC_CTX *mem_ctx, const struct dom_sid *sid)
116 {
117         char *sidstr, *result;
118
119         sidstr = sid_string_talloc(talloc_tos(), sid);
120         if (sidstr == NULL) {
121                 return NULL;
122         }
123
124         result = talloc_asprintf(mem_ctx, "%s%s", GROUP_PREFIX, sidstr);
125
126         TALLOC_FREE(sidstr);
127         return result;
128 }
129
130 /****************************************************************************
131 ****************************************************************************/
132 static bool add_mapping_entry(GROUP_MAP *map, int flag)
133 {
134         char *key, *buf;
135         int len;
136         NTSTATUS status;
137
138         key = group_mapping_key(talloc_tos(), &map->sid);
139         if (key == NULL) {
140                 return false;
141         }
142
143         len = tdb_pack(NULL, 0, "ddff",
144                 map->gid, map->sid_name_use, map->nt_name, map->comment);
145
146         buf = TALLOC_ARRAY(key, char, len);
147         if (!buf) {
148                 TALLOC_FREE(key);
149                 return false;
150         }
151         len = tdb_pack((uint8 *)buf, len, "ddff", map->gid,
152                        map->sid_name_use, map->nt_name, map->comment);
153
154         status = dbwrap_trans_store(
155                 db, string_term_tdb_data(key),
156                 make_tdb_data((uint8_t *)buf, len), TDB_REPLACE);
157
158         TALLOC_FREE(key);
159
160         return NT_STATUS_IS_OK(status);
161 }
162
163
164 /****************************************************************************
165  Return the sid and the type of the unix group.
166 ****************************************************************************/
167
168 static bool get_group_map_from_sid(struct dom_sid sid, GROUP_MAP *map)
169 {
170         TDB_DATA dbuf;
171         char *key;
172         int ret = 0;
173
174         /* the key is the SID, retrieving is direct */
175
176         key = group_mapping_key(talloc_tos(), &sid);
177         if (key == NULL) {
178                 return false;
179         }
180
181         dbuf = dbwrap_fetch_bystring(db, key, key);
182         if (dbuf.dptr == NULL) {
183                 TALLOC_FREE(key);
184                 return false;
185         }
186
187         ret = tdb_unpack(dbuf.dptr, dbuf.dsize, "ddff",
188                         &map->gid, &map->sid_name_use,
189                         &map->nt_name, &map->comment);
190
191         TALLOC_FREE(key);
192
193         if ( ret == -1 ) {
194                 DEBUG(3,("get_group_map_from_sid: tdb_unpack failure\n"));
195                 return false;
196         }
197
198         sid_copy(&map->sid, &sid);
199
200         return true;
201 }
202
203 static bool dbrec2map(const struct db_record *rec, GROUP_MAP *map)
204 {
205         if ((rec->key.dsize < strlen(GROUP_PREFIX))
206             || (strncmp((char *)rec->key.dptr, GROUP_PREFIX,
207                         GROUP_PREFIX_LEN) != 0)) {
208                 return False;
209         }
210
211         if (!string_to_sid(&map->sid, (const char *)rec->key.dptr
212                            + GROUP_PREFIX_LEN)) {
213                 return False;
214         }
215
216         return tdb_unpack(rec->value.dptr, rec->value.dsize, "ddff",
217                           &map->gid, &map->sid_name_use, &map->nt_name,
218                           &map->comment) != -1;
219 }
220
221 struct find_map_state {
222         bool found;
223         const char *name;       /* If != NULL, look for name */
224         gid_t gid;              /* valid iff name == NULL */
225         GROUP_MAP *map;
226 };
227
228 static int find_map(struct db_record *rec, void *private_data)
229 {
230         struct find_map_state *state = (struct find_map_state *)private_data;
231
232         if (!dbrec2map(rec, state->map)) {
233                 DEBUG(10, ("failed to unpack map\n"));
234                 return 0;
235         }
236
237         if (state->name != NULL) {
238                 if (strequal(state->name, state->map->nt_name)) {
239                         state->found = true;
240                         return 1;
241                 }
242         }
243         else {
244                 if (state->map->gid == state->gid) {
245                         state->found = true;
246                         return 1;
247                 }
248         }
249
250         return 0;
251 }
252
253 /****************************************************************************
254  Return the sid and the type of the unix group.
255 ****************************************************************************/
256
257 static bool get_group_map_from_gid(gid_t gid, GROUP_MAP *map)
258 {
259         struct find_map_state state;
260
261         state.found = false;
262         state.name = NULL;      /* Indicate we're looking for gid */
263         state.gid = gid;
264         state.map = map;
265
266         db->traverse_read(db, find_map, (void *)&state);
267
268         return state.found;
269 }
270
271 /****************************************************************************
272  Return the sid and the type of the unix group.
273 ****************************************************************************/
274
275 static bool get_group_map_from_ntname(const char *name, GROUP_MAP *map)
276 {
277         struct find_map_state state;
278
279         state.found = false;
280         state.name = name;
281         state.map = map;
282
283         db->traverse_read(db, find_map, (void *)&state);
284
285         return state.found;
286 }
287
288 /****************************************************************************
289  Remove a group mapping entry.
290 ****************************************************************************/
291
292 static bool group_map_remove(const struct dom_sid *sid)
293 {
294         char *key;
295         NTSTATUS status;
296
297         key = group_mapping_key(talloc_tos(), sid);
298         if (key == NULL) {
299                 return false;
300         }
301
302         status = dbwrap_trans_delete(db, string_term_tdb_data(key));
303
304         TALLOC_FREE(key);
305         return NT_STATUS_IS_OK(status);
306 }
307
308 /****************************************************************************
309  Enumerate the group mapping.
310 ****************************************************************************/
311
312 struct enum_map_state {
313         const struct dom_sid *domsid;
314         enum lsa_SidType sid_name_use;
315         bool unix_only;
316
317         size_t num_maps;
318         GROUP_MAP *maps;
319 };
320
321 static int collect_map(struct db_record *rec, void *private_data)
322 {
323         struct enum_map_state *state = (struct enum_map_state *)private_data;
324         GROUP_MAP map;
325         GROUP_MAP *tmp;
326
327         if (!dbrec2map(rec, &map)) {
328                 return 0;
329         }
330         /* list only the type or everything if UNKNOWN */
331         if (state->sid_name_use != SID_NAME_UNKNOWN
332             && state->sid_name_use != map.sid_name_use) {
333                 DEBUG(11,("enum_group_mapping: group %s is not of the "
334                           "requested type\n", map.nt_name));
335                 return 0;
336         }
337
338         if ((state->unix_only == ENUM_ONLY_MAPPED) && (map.gid == -1)) {
339                 DEBUG(11,("enum_group_mapping: group %s is non mapped\n",
340                           map.nt_name));
341                 return 0;
342         }
343
344         if ((state->domsid != NULL) &&
345             (dom_sid_compare_domain(state->domsid, &map.sid) != 0)) {
346                 DEBUG(11,("enum_group_mapping: group %s is not in domain\n",
347                           sid_string_dbg(&map.sid)));
348                 return 0;
349         }
350
351         if (!(tmp = SMB_REALLOC_ARRAY(state->maps, GROUP_MAP,
352                                       state->num_maps+1))) {
353                 DEBUG(0,("enum_group_mapping: Unable to enlarge group "
354                          "map!\n"));
355                 return 1;
356         }
357
358         state->maps = tmp;
359         state->maps[state->num_maps] = map;
360         state->num_maps++;
361         return 0;
362 }
363
364 static bool enum_group_mapping(const struct dom_sid *domsid,
365                                enum lsa_SidType sid_name_use,
366                                GROUP_MAP **pp_rmap,
367                                size_t *p_num_entries, bool unix_only)
368 {
369         struct enum_map_state state;
370
371         state.domsid = domsid;
372         state.sid_name_use = sid_name_use;
373         state.unix_only = unix_only;
374         state.num_maps = 0;
375         state.maps = NULL;
376
377         if (db->traverse_read(db, collect_map, (void *)&state) < 0) {
378                 return false;
379         }
380
381         *pp_rmap = state.maps;
382         *p_num_entries = state.num_maps;
383
384         return true;
385 }
386
387 /* This operation happens on session setup, so it should better be fast. We
388  * store a list of aliases a SID is member of hanging off MEMBEROF/SID. */
389
390 static NTSTATUS one_alias_membership(const struct dom_sid *member,
391                                struct dom_sid **sids, size_t *num)
392 {
393         fstring tmp;
394         fstring key;
395         char *string_sid;
396         TDB_DATA dbuf;
397         const char *p;
398         NTSTATUS status = NT_STATUS_OK;
399         TALLOC_CTX *frame = talloc_stackframe();
400
401         slprintf(key, sizeof(key), "%s%s", MEMBEROF_PREFIX,
402                  sid_to_fstring(tmp, member));
403
404         dbuf = dbwrap_fetch_bystring(db, frame, key);
405         if (dbuf.dptr == NULL) {
406                 TALLOC_FREE(frame);
407                 return NT_STATUS_OK;
408         }
409
410         p = (const char *)dbuf.dptr;
411
412         while (next_token_talloc(frame, &p, &string_sid, " ")) {
413                 struct dom_sid alias;
414                 uint32_t num_sids;
415
416                 if (!string_to_sid(&alias, string_sid))
417                         continue;
418
419                 num_sids = *num;
420                 status= add_sid_to_array_unique(NULL, &alias, sids, &num_sids);
421                 if (!NT_STATUS_IS_OK(status)) {
422                         goto done;
423                 }
424                 *num = num_sids;
425         }
426
427 done:
428         TALLOC_FREE(frame);
429         return status;
430 }
431
432 static NTSTATUS alias_memberships(const struct dom_sid *members, size_t num_members,
433                                   struct dom_sid **sids, size_t *num)
434 {
435         size_t i;
436
437         *num = 0;
438         *sids = NULL;
439
440         for (i=0; i<num_members; i++) {
441                 NTSTATUS status = one_alias_membership(&members[i], sids, num);
442                 if (!NT_STATUS_IS_OK(status))
443                         return status;
444         }
445         return NT_STATUS_OK;
446 }
447
448 static bool is_aliasmem(const struct dom_sid *alias, const struct dom_sid *member)
449 {
450         struct dom_sid *sids;
451         size_t i;
452         size_t num;
453
454         /* This feels the wrong way round, but the on-disk data structure
455          * dictates it this way. */
456         if (!NT_STATUS_IS_OK(alias_memberships(member, 1, &sids, &num)))
457                 return False;
458
459         for (i=0; i<num; i++) {
460                 if (dom_sid_compare(alias, &sids[i]) == 0) {
461                         TALLOC_FREE(sids);
462                         return True;
463                 }
464         }
465         TALLOC_FREE(sids);
466         return False;
467 }
468
469
470 static NTSTATUS add_aliasmem(const struct dom_sid *alias, const struct dom_sid *member)
471 {
472         GROUP_MAP map;
473         char *key;
474         fstring string_sid;
475         char *new_memberstring;
476         struct db_record *rec;
477         NTSTATUS status;
478
479         if (!get_group_map_from_sid(*alias, &map))
480                 return NT_STATUS_NO_SUCH_ALIAS;
481
482         if ( (map.sid_name_use != SID_NAME_ALIAS) &&
483              (map.sid_name_use != SID_NAME_WKN_GRP) )
484                 return NT_STATUS_NO_SUCH_ALIAS;
485
486         if (is_aliasmem(alias, member))
487                 return NT_STATUS_MEMBER_IN_ALIAS;
488
489         sid_to_fstring(string_sid, member);
490
491         key = talloc_asprintf(talloc_tos(), "%s%s", MEMBEROF_PREFIX,
492                               string_sid);
493         if (key == NULL) {
494                 return NT_STATUS_NO_MEMORY;
495         }
496
497         if (db->transaction_start(db) != 0) {
498                 DEBUG(0, ("transaction_start failed\n"));
499                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
500         }
501
502         rec = db->fetch_locked(db, key, string_term_tdb_data(key));
503
504         if (rec == NULL) {
505                 DEBUG(10, ("fetch_lock failed\n"));
506                 TALLOC_FREE(key);
507                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
508                 goto cancel;
509         }
510
511         sid_to_fstring(string_sid, alias);
512
513         if (rec->value.dptr != NULL) {
514                 new_memberstring = talloc_asprintf(
515                         key, "%s %s", (char *)(rec->value.dptr), string_sid);
516         } else {
517                 new_memberstring = talloc_strdup(key, string_sid);
518         }
519
520         if (new_memberstring == NULL) {
521                 TALLOC_FREE(key);
522                 status = NT_STATUS_NO_MEMORY;
523                 goto cancel;
524         }
525
526         status = rec->store(rec, string_term_tdb_data(new_memberstring), 0);
527
528         TALLOC_FREE(key);
529
530         if (!NT_STATUS_IS_OK(status)) {
531                 DEBUG(10, ("Could not store record: %s\n", nt_errstr(status)));
532                 goto cancel;
533         }
534
535         if (db->transaction_commit(db) != 0) {
536                 DEBUG(0, ("transaction_commit failed\n"));
537                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
538                 return status;
539         }
540
541         return NT_STATUS_OK;
542
543  cancel:
544         if (db->transaction_cancel(db) != 0) {
545                 smb_panic("transaction_cancel failed");
546         }
547
548         return status;
549 }
550
551 struct aliasmem_state {
552         TALLOC_CTX *mem_ctx;
553         const struct dom_sid *alias;
554         struct dom_sid **sids;
555         size_t *num;
556 };
557
558 static int collect_aliasmem(struct db_record *rec, void *priv)
559 {
560         struct aliasmem_state *state = (struct aliasmem_state *)priv;
561         const char *p;
562         char *alias_string;
563         TALLOC_CTX *frame;
564
565         if (strncmp((const char *)rec->key.dptr, MEMBEROF_PREFIX,
566                     MEMBEROF_PREFIX_LEN) != 0)
567                 return 0;
568
569         p = (const char *)rec->value.dptr;
570
571         frame = talloc_stackframe();
572
573         while (next_token_talloc(frame, &p, &alias_string, " ")) {
574                 struct dom_sid alias, member;
575                 const char *member_string;
576                 uint32_t num_sids;
577
578                 if (!string_to_sid(&alias, alias_string))
579                         continue;
580
581                 if (dom_sid_compare(state->alias, &alias) != 0)
582                         continue;
583
584                 /* Ok, we found the alias we're looking for in the membership
585                  * list currently scanned. The key represents the alias
586                  * member. Add that. */
587
588                 member_string = strchr((const char *)rec->key.dptr, '/');
589
590                 /* Above we tested for MEMBEROF_PREFIX which includes the
591                  * slash. */
592
593                 SMB_ASSERT(member_string != NULL);
594                 member_string += 1;
595
596                 if (!string_to_sid(&member, member_string))
597                         continue;
598
599                 num_sids = *state->num;
600                 if (!NT_STATUS_IS_OK(add_sid_to_array(state->mem_ctx, &member,
601                                                       state->sids,
602                                                       &num_sids)))
603                 {
604                         /* talloc fail. */
605                         break;
606                 }
607                 *state->num = num_sids;
608         }
609
610         TALLOC_FREE(frame);
611         return 0;
612 }
613
614 static NTSTATUS enum_aliasmem(const struct dom_sid *alias, TALLOC_CTX *mem_ctx,
615                               struct dom_sid **sids, size_t *num)
616 {
617         GROUP_MAP map;
618         struct aliasmem_state state;
619
620         if (!get_group_map_from_sid(*alias, &map))
621                 return NT_STATUS_NO_SUCH_ALIAS;
622
623         if ( (map.sid_name_use != SID_NAME_ALIAS) &&
624              (map.sid_name_use != SID_NAME_WKN_GRP) )
625                 return NT_STATUS_NO_SUCH_ALIAS;
626
627         *sids = NULL;
628         *num = 0;
629
630         state.alias = alias;
631         state.sids = sids;
632         state.num = num;
633         state.mem_ctx = mem_ctx;
634
635         db->traverse_read(db, collect_aliasmem, &state);
636         return NT_STATUS_OK;
637 }
638
639 static NTSTATUS del_aliasmem(const struct dom_sid *alias, const struct dom_sid *member)
640 {
641         NTSTATUS status;
642         struct dom_sid *sids;
643         size_t i, num;
644         bool found = False;
645         char *member_string;
646         char *key;
647         fstring sid_string;
648
649         if (db->transaction_start(db) != 0) {
650                 DEBUG(0, ("transaction_start failed\n"));
651                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
652         }
653
654         status = alias_memberships(member, 1, &sids, &num);
655
656         if (!NT_STATUS_IS_OK(status)) {
657                 goto cancel;
658         }
659
660         for (i=0; i<num; i++) {
661                 if (dom_sid_compare(&sids[i], alias) == 0) {
662                         found = True;
663                         break;
664                 }
665         }
666
667         if (!found) {
668                 TALLOC_FREE(sids);
669                 status = NT_STATUS_MEMBER_NOT_IN_ALIAS;
670                 goto cancel;
671         }
672
673         if (i < num)
674                 sids[i] = sids[num-1];
675
676         num -= 1;
677
678         sid_to_fstring(sid_string, member);
679
680         key = talloc_asprintf(sids, "%s%s", MEMBEROF_PREFIX, sid_string);
681         if (key == NULL) {
682                 TALLOC_FREE(sids);
683                 status = NT_STATUS_NO_MEMORY;
684                 goto cancel;
685         }
686
687         if (num == 0) {
688                 status = dbwrap_delete_bystring(db, key);
689                 goto commit;
690         }
691
692         member_string = talloc_strdup(sids, "");
693         if (member_string == NULL) {
694                 TALLOC_FREE(sids);
695                 status = NT_STATUS_NO_MEMORY;
696                 goto cancel;
697         }
698
699         for (i=0; i<num; i++) {
700
701                 sid_to_fstring(sid_string, &sids[i]);
702
703                 member_string = talloc_asprintf_append_buffer(
704                         member_string, " %s", sid_string);
705
706                 if (member_string == NULL) {
707                         TALLOC_FREE(sids);
708                         status = NT_STATUS_NO_MEMORY;
709                         goto cancel;
710                 }
711         }
712
713         status = dbwrap_store_bystring(
714                 db, key, string_term_tdb_data(member_string), 0);
715  commit:
716         TALLOC_FREE(sids);
717
718         if (!NT_STATUS_IS_OK(status)) {
719                 DEBUG(10, ("dbwrap_store_bystring failed: %s\n",
720                            nt_errstr(status)));
721                 goto cancel;
722         }
723
724         if (db->transaction_commit(db) != 0) {
725                 DEBUG(0, ("transaction_commit failed\n"));
726                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
727                 return status;
728         }
729
730         return NT_STATUS_OK;
731
732  cancel:
733         if (db->transaction_cancel(db) != 0) {
734                 smb_panic("transaction_cancel failed");
735         }
736         return status;
737 }
738
739
740 /* -- ldb->tdb switching code -------------------------------------------- */
741
742 /* change this if the data format ever changes */
743 #define LTDB_PACKING_FORMAT 0x26011967
744
745 /* old packing formats (not supported for now,
746  * it was never used for group mapping AFAIK) */
747 #define LTDB_PACKING_FORMAT_NODN 0x26011966
748
749 static unsigned int pull_uint32(uint8_t *p, int ofs)
750 {
751         p += ofs;
752         return p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
753 }
754
755 /*
756   unpack a ldb message from a linear buffer in TDB_DATA
757 */
758 static int convert_ldb_record(TDB_CONTEXT *ltdb, TDB_DATA key,
759                               TDB_DATA data, void *ptr)
760 {
761         TALLOC_CTX *tmp_ctx = talloc_tos();
762         GROUP_MAP map;
763         uint8_t *p;
764         uint32_t format;
765         uint32_t num_el;
766         unsigned int remaining;
767         unsigned int i, j;
768         size_t len;
769         char *name;
770         char *val;
771         char *q;
772         uint32_t num_mem = 0;
773         struct dom_sid *members = NULL;
774
775         p = (uint8_t *)data.dptr;
776         if (data.dsize < 8) {
777                 errno = EIO;
778                 goto failed;
779         }
780
781         format = pull_uint32(p, 0);
782         num_el = pull_uint32(p, 4);
783         p += 8;
784
785         remaining = data.dsize - 8;
786
787         switch (format) {
788         case LTDB_PACKING_FORMAT:
789                 len = strnlen((char *)p, remaining);
790                 if (len == remaining) {
791                         errno = EIO;
792                         goto failed;
793                 }
794
795                 if (*p == '@') {
796                         /* ignore special LDB attributes */
797                         return 0;
798                 }
799
800                 if (strncmp((char *)p, "rid=", 4)) {
801                         /* unknown entry, ignore */
802                         DEBUG(3, ("Found unknown entry in group mapping "
803                                   "database named [%s]\n", (char *)p));
804                         return 0;
805                 }
806
807                 remaining -= len + 1;
808                 p += len + 1;
809                 break;
810
811         case LTDB_PACKING_FORMAT_NODN:
812         default:
813                 errno = EIO;
814                 goto failed;
815         }
816
817         if (num_el == 0) {
818                 /* bad entry, ignore */
819                 return 0;
820         }
821
822         if (num_el > remaining / 6) {
823                 errno = EIO;
824                 goto failed;
825         }
826
827         ZERO_STRUCT(map);
828
829         for (i = 0; i < num_el; i++) {
830                 uint32_t num_vals;
831
832                 if (remaining < 10) {
833                         errno = EIO;
834                         goto failed;
835                 }
836                 len = strnlen((char *)p, remaining - 6);
837                 if (len == remaining - 6) {
838                         errno = EIO;
839                         goto failed;
840                 }
841                 name = talloc_strndup(tmp_ctx, (char *)p, len);
842                 if (name == NULL) {
843                         errno = ENOMEM;
844                         goto failed;
845                 }
846                 remaining -= len + 1;
847                 p += len + 1;
848
849                 num_vals = pull_uint32(p, 0);
850                 if (StrCaseCmp(name, "member") == 0) {
851                         num_mem = num_vals;
852                         members = talloc_array(tmp_ctx, struct dom_sid, num_mem);
853                         if (members == NULL) {
854                                 errno = ENOMEM;
855                                 goto failed;
856                         }
857                 } else if (num_vals != 1) {
858                         errno = EIO;
859                         goto failed;
860                 }
861
862                 p += 4;
863                 remaining -= 4;
864
865                 for (j = 0; j < num_vals; j++) {
866                         len = pull_uint32(p, 0);
867                         if (len > remaining-5) {
868                                 errno = EIO;
869                                 goto failed;
870                         }
871
872                         val = talloc_strndup(tmp_ctx, (char *)(p + 4), len);
873                         if (val == NULL) {
874                                 errno = ENOMEM;
875                                 goto failed;
876                         }
877
878                         remaining -= len+4+1;
879                         p += len+4+1;
880
881                         /* we ignore unknown or uninteresting attributes
882                          * (objectclass, etc.) */
883                         if (StrCaseCmp(name, "gidNumber") == 0) {
884                                 map.gid = strtoul(val, &q, 10);
885                                 if (*q) {
886                                         errno = EIO;
887                                         goto failed;
888                                 }
889                         } else if (StrCaseCmp(name, "sid") == 0) {
890                                 if (!string_to_sid(&map.sid, val)) {
891                                         errno = EIO;
892                                         goto failed;
893                                 }
894                         } else if (StrCaseCmp(name, "sidNameUse") == 0) {
895                                 map.sid_name_use = strtoul(val, &q, 10);
896                                 if (*q) {
897                                         errno = EIO;
898                                         goto failed;
899                                 }
900                         } else if (StrCaseCmp(name, "ntname") == 0) {
901                                 strlcpy(map.nt_name, val,
902                                         sizeof(map.nt_name) -1);
903                         } else if (StrCaseCmp(name, "comment") == 0) {
904                                 strlcpy(map.comment, val,
905                                         sizeof(map.comment) -1);
906                         } else if (StrCaseCmp(name, "member") == 0) {
907                                 if (!string_to_sid(&members[j], val)) {
908                                         errno = EIO;
909                                         goto failed;
910                                 }
911                         }
912
913                         TALLOC_FREE(val);
914                 }
915
916                 TALLOC_FREE(name);
917         }
918
919         if (!add_mapping_entry(&map, 0)) {
920                 errno = EIO;
921                 goto failed;
922         }
923
924         if (num_mem) {
925                 for (j = 0; j < num_mem; j++) {
926                         NTSTATUS status;
927                         status = add_aliasmem(&map.sid, &members[j]);
928                         if (!NT_STATUS_IS_OK(status)) {
929                                 errno = EIO;
930                                 goto failed;
931                         }
932                 }
933         }
934
935         if (remaining != 0) {
936                 DEBUG(0, ("Errror: %d bytes unread in ltdb_unpack_data\n",
937                           remaining));
938         }
939
940         return 0;
941
942 failed:
943         return -1;
944 }
945
946 static bool mapping_switch(const char *ldb_path)
947 {
948         TDB_CONTEXT *ltdb;
949         TALLOC_CTX *frame;
950         char *new_path;
951         int ret;
952
953         frame = talloc_stackframe();
954
955         ltdb = tdb_open_log(ldb_path, 0, TDB_DEFAULT, O_RDONLY, 0600);
956         if (ltdb == NULL) goto failed;
957
958         /* ldb is just a very fancy tdb, read out raw data and perform
959          * conversion */
960         ret = tdb_traverse(ltdb, convert_ldb_record, NULL);
961         if (ret == -1) goto failed;
962
963         if (ltdb) {
964                 tdb_close(ltdb);
965                 ltdb = NULL;
966         }
967
968         /* now rename the old db out of the way */
969         new_path = state_path("group_mapping.ldb.replaced");
970         if (!new_path) {
971                 goto failed;
972         }
973         if (rename(ldb_path, new_path) != 0) {
974                 DEBUG(0,("Failed to rename old group mapping database\n"));
975                 goto failed;
976         }
977         TALLOC_FREE(frame);
978         return True;
979
980 failed:
981         DEBUG(0, ("Failed to switch to tdb group mapping database\n"));
982         if (ltdb) tdb_close(ltdb);
983         TALLOC_FREE(frame);
984         return False;
985 }
986
987 static const struct mapping_backend tdb_backend = {
988         .add_mapping_entry         = add_mapping_entry,
989         .get_group_map_from_sid    = get_group_map_from_sid,
990         .get_group_map_from_gid    = get_group_map_from_gid,
991         .get_group_map_from_ntname = get_group_map_from_ntname,
992         .group_map_remove          = group_map_remove,
993         .enum_group_mapping        = enum_group_mapping,
994         .one_alias_membership      = one_alias_membership,
995         .add_aliasmem              = add_aliasmem,
996         .del_aliasmem              = del_aliasmem,
997         .enum_aliasmem             = enum_aliasmem      
998 };
999
1000 /*
1001   initialise the tdb mapping backend
1002  */
1003 const struct mapping_backend *groupdb_tdb_init(void)
1004 {
1005         if (!init_group_mapping()) {
1006                 DEBUG(0,("Failed to initialise tdb mapping backend\n"));
1007                 return NULL;
1008         }
1009
1010         return &tdb_backend;
1011 }