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