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