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