tdb: introduce TDB_SUPPORTED_FEATURE_FLAGS
[Samba.git] / source3 / groupdb / mapping_tdb.c
blobcc397d964fd86ca003bf28f1f62dde058505011c
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.
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.
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/>.
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"
33 static struct db_context *db; /* used for driver files */
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);
42 static bool mapping_switch(const char *ldb_path);
44 /****************************************************************************
45 Open the group mapping tdb.
46 ****************************************************************************/
47 static bool init_group_mapping(void)
49 const char *ldb_path;
51 if (db != NULL) {
52 return true;
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;
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;
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;
77 /* handle a Samba upgrade */
78 tdb_lock_bystring(tdb, vstring);
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)) {
85 * Written on a bigendian machine with old fetch_int
86 * code. Save as le.
88 tdb_store_int32(tdb, vstring, DATABASE_VERSION_V2);
89 vers_id = DATABASE_VERSION_V2;
92 /* if its an unknown version we remove everthing in the db */
94 if (vers_id != DATABASE_VERSION_V2) {
95 tdb_wipe_all(tdb);
96 tdb_store_int32(tdb, vstring, DATABASE_VERSION_V2);
99 tdb_unlock_bystring(tdb, vstring);
101 /* cleanup any map entries with a gid == -1 */
103 if ( enum_group_mapping( NULL, SID_NAME_UNKNOWN, &map_table,
104 &num_entries, False ) ) {
105 int i;
107 for ( i=0; i<num_entries; i++ ) {
108 if ( map_table[i].gid == -1 ) {
109 group_map_remove( &map_table[i].sid );
113 SAFE_FREE( map_table );
115 #endif
117 return true;
120 static char *group_mapping_key(TALLOC_CTX *mem_ctx, const struct dom_sid *sid)
122 char sidstr[DOM_SID_STR_BUFLEN];
123 int len;
125 len = dom_sid_string_buf(sid, sidstr, sizeof(sidstr));
126 if (len >= sizeof(sidstr)) {
127 return NULL;
130 return talloc_asprintf(mem_ctx, "%s%s", GROUP_PREFIX, sidstr);
133 /****************************************************************************
134 ****************************************************************************/
135 static bool add_mapping_entry(GROUP_MAP *map, int flag)
137 char *key, *buf;
138 int len;
139 NTSTATUS status;
141 key = group_mapping_key(talloc_tos(), &map->sid);
142 if (key == NULL) {
143 return false;
146 len = tdb_pack(NULL, 0, "ddff",
147 map->gid, map->sid_name_use, map->nt_name, map->comment);
149 buf = talloc_array(key, char, len);
150 if (!buf) {
151 TALLOC_FREE(key);
152 return false;
154 len = tdb_pack((uint8 *)buf, len, "ddff", map->gid,
155 map->sid_name_use, map->nt_name, map->comment);
157 status = dbwrap_trans_store(
158 db, string_term_tdb_data(key),
159 make_tdb_data((uint8_t *)buf, len), TDB_REPLACE);
161 TALLOC_FREE(key);
163 return NT_STATUS_IS_OK(status);
167 /****************************************************************************
168 Return the sid and the type of the unix group.
169 ****************************************************************************/
171 static bool get_group_map_from_sid(struct dom_sid sid, GROUP_MAP *map)
173 TDB_DATA dbuf;
174 char *key;
175 int ret = 0;
176 NTSTATUS status;
177 fstring nt_name;
178 fstring comment;
180 /* the key is the SID, retrieving is direct */
182 key = group_mapping_key(talloc_tos(), &sid);
183 if (key == NULL) {
184 return false;
187 status = dbwrap_fetch_bystring(db, key, key, &dbuf);
188 if (!NT_STATUS_IS_OK(status)) {
189 TALLOC_FREE(key);
190 return false;
193 ret = tdb_unpack(dbuf.dptr, dbuf.dsize, "ddff",
194 &map->gid, &map->sid_name_use,
195 &nt_name, &comment);
197 TALLOC_FREE(key);
199 if ( ret == -1 ) {
200 DEBUG(3,("get_group_map_from_sid: tdb_unpack failure\n"));
201 return false;
204 sid_copy(&map->sid, &sid);
206 map->nt_name = talloc_strdup(map, nt_name);
207 if (!map->nt_name) {
208 return false;
210 map->comment = talloc_strdup(map, comment);
211 if (!map->comment) {
212 return false;
215 return true;
218 static bool dbrec2map(const struct db_record *rec, GROUP_MAP *map)
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;
226 if ((key.dsize < strlen(GROUP_PREFIX))
227 || (strncmp((char *)key.dptr, GROUP_PREFIX,
228 GROUP_PREFIX_LEN) != 0)) {
229 return False;
232 if (!string_to_sid(&map->sid, (const char *)key.dptr
233 + GROUP_PREFIX_LEN)) {
234 return False;
237 ret = tdb_unpack(value.dptr, value.dsize, "ddff",
238 &map->gid, &map->sid_name_use,
239 &nt_name, &comment);
241 if (ret == -1) {
242 DEBUG(3, ("dbrec2map: tdb_unpack failure\n"));
243 return false;
246 map->nt_name = talloc_strdup(map, nt_name);
247 if (!map->nt_name) {
248 return false;
250 map->comment = talloc_strdup(map, comment);
251 if (!map->comment) {
252 return false;
255 return true;
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;
265 static int find_map(struct db_record *rec, void *private_data)
267 struct find_map_state *state = (struct find_map_state *)private_data;
269 if (!dbrec2map(rec, state->map)) {
270 DEBUG(10, ("failed to unpack map\n"));
271 return 0;
274 if (state->name != NULL) {
275 if (strequal(state->name, state->map->nt_name)) {
276 state->found = true;
277 return 1;
280 else {
281 if (state->map->gid == state->gid) {
282 state->found = true;
283 return 1;
287 return 0;
290 /****************************************************************************
291 Return the sid and the type of the unix group.
292 ****************************************************************************/
294 static bool get_group_map_from_gid(gid_t gid, GROUP_MAP *map)
296 struct find_map_state state;
298 state.found = false;
299 state.name = NULL; /* Indicate we're looking for gid */
300 state.gid = gid;
301 state.map = map;
303 dbwrap_traverse_read(db, find_map, (void *)&state, NULL);
305 return state.found;
308 /****************************************************************************
309 Return the sid and the type of the unix group.
310 ****************************************************************************/
312 static bool get_group_map_from_ntname(const char *name, GROUP_MAP *map)
314 struct find_map_state state;
316 state.found = false;
317 state.name = name;
318 state.map = map;
320 dbwrap_traverse_read(db, find_map, (void *)&state, NULL);
322 return state.found;
325 /****************************************************************************
326 Remove a group mapping entry.
327 ****************************************************************************/
329 static bool group_map_remove(const struct dom_sid *sid)
331 char *key;
332 NTSTATUS status;
334 key = group_mapping_key(talloc_tos(), sid);
335 if (key == NULL) {
336 return false;
339 status = dbwrap_trans_delete(db, string_term_tdb_data(key));
341 TALLOC_FREE(key);
342 return NT_STATUS_IS_OK(status);
345 /****************************************************************************
346 Enumerate the group mapping.
347 ****************************************************************************/
349 struct enum_map_state {
350 const struct dom_sid *domsid;
351 enum lsa_SidType sid_name_use;
352 bool unix_only;
354 size_t num_maps;
355 GROUP_MAP **maps;
358 static int collect_map(struct db_record *rec, void *private_data)
360 struct enum_map_state *state = (struct enum_map_state *)private_data;
361 GROUP_MAP *map;
362 GROUP_MAP **tmp;
364 map = talloc_zero(NULL, GROUP_MAP);
365 if (!map) {
366 DEBUG(0, ("Unable to allocate group map!\n"));
367 return 1;
370 if (!dbrec2map(rec, map)) {
371 TALLOC_FREE(map);
372 return 0;
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;
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;
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;
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;
407 state->maps = tmp;
408 state->maps[state->num_maps] = talloc_move(state->maps, &map);
409 state->num_maps++;
410 return 0;
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)
418 struct enum_map_state state;
419 NTSTATUS status;
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;
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;
433 *pp_rmap = state.maps;
434 *p_num_entries = state.num_maps;
436 return true;
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. */
442 static NTSTATUS one_alias_membership(const struct dom_sid *member,
443 struct dom_sid **sids, size_t *num)
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();
453 slprintf(key, sizeof(key), "%s%s", MEMBEROF_PREFIX,
454 sid_to_fstring(tmp, member));
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;
462 p = (const char *)dbuf.dptr;
464 while (next_token_talloc(frame, &p, &string_sid, " ")) {
465 struct dom_sid alias;
466 uint32_t num_sids;
468 if (!string_to_sid(&alias, string_sid))
469 continue;
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;
476 *num = num_sids;
479 done:
480 TALLOC_FREE(frame);
481 return status;
484 static NTSTATUS alias_memberships(const struct dom_sid *members, size_t num_members,
485 struct dom_sid **sids, size_t *num)
487 size_t i;
489 *num = 0;
490 *sids = NULL;
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;
497 return NT_STATUS_OK;
500 static bool is_aliasmem(const struct dom_sid *alias, const struct dom_sid *member)
502 struct dom_sid *sids;
503 size_t i;
504 size_t num;
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;
511 for (i=0; i<num; i++) {
512 if (dom_sid_compare(alias, &sids[i]) == 0) {
513 TALLOC_FREE(sids);
514 return True;
517 TALLOC_FREE(sids);
518 return False;
522 static NTSTATUS add_aliasmem(const struct dom_sid *alias, const struct dom_sid *member)
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;
532 map = talloc_zero(talloc_tos(), GROUP_MAP);
533 if (!map) {
534 return NT_STATUS_NO_MEMORY;
537 if (!get_group_map_from_sid(*alias, map)) {
538 TALLOC_FREE(map);
539 return NT_STATUS_NO_SUCH_ALIAS;
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;
548 TALLOC_FREE(map);
550 if (is_aliasmem(alias, member))
551 return NT_STATUS_MEMBER_IN_ALIAS;
553 sid_to_fstring(string_sid, member);
555 key = talloc_asprintf(talloc_tos(), "%s%s", MEMBEROF_PREFIX,
556 string_sid);
557 if (key == NULL) {
558 return NT_STATUS_NO_MEMORY;
561 if (dbwrap_transaction_start(db) != 0) {
562 DEBUG(0, ("transaction_start failed\n"));
563 return NT_STATUS_INTERNAL_DB_CORRUPTION;
566 rec = dbwrap_fetch_locked(db, key, string_term_tdb_data(key));
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;
575 value = dbwrap_record_get_value(rec);
577 sid_to_fstring(string_sid, alias);
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);
586 if (new_memberstring == NULL) {
587 TALLOC_FREE(key);
588 status = NT_STATUS_NO_MEMORY;
589 goto cancel;
592 status = dbwrap_record_store(rec, string_term_tdb_data(new_memberstring), 0);
594 TALLOC_FREE(key);
596 if (!NT_STATUS_IS_OK(status)) {
597 DEBUG(10, ("Could not store record: %s\n", nt_errstr(status)));
598 goto cancel;
601 if (dbwrap_transaction_commit(db) != 0) {
602 DEBUG(0, ("transaction_commit failed\n"));
603 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
604 return status;
607 return NT_STATUS_OK;
609 cancel:
610 if (dbwrap_transaction_cancel(db) != 0) {
611 smb_panic("transaction_cancel failed");
614 return status;
617 struct aliasmem_state {
618 TALLOC_CTX *mem_ctx;
619 const struct dom_sid *alias;
620 struct dom_sid **sids;
621 size_t *num;
624 static int collect_aliasmem(struct db_record *rec, void *priv)
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);
633 if (strncmp((const char *)key.dptr, MEMBEROF_PREFIX,
634 MEMBEROF_PREFIX_LEN) != 0)
635 return 0;
637 p = (const char *)value.dptr;
639 frame = talloc_stackframe();
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;
646 if (!string_to_sid(&alias, alias_string))
647 continue;
649 if (dom_sid_compare(state->alias, &alias) != 0)
650 continue;
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. */
656 member_string = strchr((const char *)key.dptr, '/');
658 /* Above we tested for MEMBEROF_PREFIX which includes the
659 * slash. */
661 SMB_ASSERT(member_string != NULL);
662 member_string += 1;
664 if (!string_to_sid(&member, member_string))
665 continue;
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)))
672 /* talloc fail. */
673 break;
675 *state->num = num_sids;
678 TALLOC_FREE(frame);
679 return 0;
682 static NTSTATUS enum_aliasmem(const struct dom_sid *alias, TALLOC_CTX *mem_ctx,
683 struct dom_sid **sids, size_t *num)
685 GROUP_MAP *map;
686 struct aliasmem_state state;
688 map = talloc_zero(talloc_tos(), GROUP_MAP);
689 if (!map) {
690 return NT_STATUS_NO_MEMORY;
693 if (!get_group_map_from_sid(*alias, map)) {
694 TALLOC_FREE(map);
695 return NT_STATUS_NO_SUCH_ALIAS;
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;
704 TALLOC_FREE(map);
706 *sids = NULL;
707 *num = 0;
709 state.alias = alias;
710 state.sids = sids;
711 state.num = num;
712 state.mem_ctx = mem_ctx;
714 dbwrap_traverse_read(db, collect_aliasmem, &state, NULL);
715 return NT_STATUS_OK;
718 static NTSTATUS del_aliasmem(const struct dom_sid *alias, const struct dom_sid *member)
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;
728 if (dbwrap_transaction_start(db) != 0) {
729 DEBUG(0, ("transaction_start failed\n"));
730 return NT_STATUS_INTERNAL_DB_CORRUPTION;
733 status = alias_memberships(member, 1, &sids, &num);
735 if (!NT_STATUS_IS_OK(status)) {
736 goto cancel;
739 for (i=0; i<num; i++) {
740 if (dom_sid_compare(&sids[i], alias) == 0) {
741 found = True;
742 break;
746 if (!found) {
747 TALLOC_FREE(sids);
748 status = NT_STATUS_MEMBER_NOT_IN_ALIAS;
749 goto cancel;
752 if (i < num)
753 sids[i] = sids[num-1];
755 num -= 1;
757 sid_to_fstring(sid_string, member);
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;
766 if (num == 0) {
767 status = dbwrap_delete_bystring(db, key);
768 goto commit;
771 member_string = talloc_strdup(sids, "");
772 if (member_string == NULL) {
773 TALLOC_FREE(sids);
774 status = NT_STATUS_NO_MEMORY;
775 goto cancel;
778 for (i=0; i<num; i++) {
780 sid_to_fstring(sid_string, &sids[i]);
782 member_string = talloc_asprintf_append_buffer(
783 member_string, " %s", sid_string);
785 if (member_string == NULL) {
786 TALLOC_FREE(sids);
787 status = NT_STATUS_NO_MEMORY;
788 goto cancel;
792 status = dbwrap_store_bystring(
793 db, key, string_term_tdb_data(member_string), 0);
794 commit:
795 TALLOC_FREE(sids);
797 if (!NT_STATUS_IS_OK(status)) {
798 DEBUG(10, ("dbwrap_store_bystring failed: %s\n",
799 nt_errstr(status)));
800 goto cancel;
803 if (dbwrap_transaction_commit(db) != 0) {
804 DEBUG(0, ("transaction_commit failed\n"));
805 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
806 return status;
809 return NT_STATUS_OK;
811 cancel:
812 if (dbwrap_transaction_cancel(db) != 0) {
813 smb_panic("transaction_cancel failed");
815 return status;
819 /* -- ldb->tdb switching code -------------------------------------------- */
821 /* change this if the data format ever changes */
822 #define LTDB_PACKING_FORMAT 0x26011967
824 /* old packing formats (not supported for now,
825 * it was never used for group mapping AFAIK) */
826 #define LTDB_PACKING_FORMAT_NODN 0x26011966
828 static unsigned int pull_uint32(uint8_t *p, int ofs)
830 p += ofs;
831 return p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
835 unpack a ldb message from a linear buffer in TDB_DATA
837 static int convert_ldb_record(TDB_CONTEXT *ltdb, TDB_DATA key,
838 TDB_DATA data, void *ptr)
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;
854 p = (uint8_t *)data.dptr;
855 if (data.dsize < 8) {
856 errno = EIO;
857 goto failed;
860 format = pull_uint32(p, 0);
861 num_el = pull_uint32(p, 4);
862 p += 8;
864 remaining = data.dsize - 8;
866 switch (format) {
867 case LTDB_PACKING_FORMAT:
868 len = strnlen((char *)p, remaining);
869 if (len == remaining) {
870 errno = EIO;
871 goto failed;
874 if (*p == '@') {
875 /* ignore special LDB attributes */
876 return 0;
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;
886 remaining -= len + 1;
887 p += len + 1;
888 break;
890 case LTDB_PACKING_FORMAT_NODN:
891 default:
892 errno = EIO;
893 goto failed;
896 if (num_el == 0) {
897 /* bad entry, ignore */
898 return 0;
901 if (num_el > remaining / 6) {
902 errno = EIO;
903 goto failed;
906 map = talloc_zero(NULL, GROUP_MAP);
907 if (!map) {
908 errno = ENOMEM;
909 goto failed;
912 for (i = 0; i < num_el; i++) {
913 uint32_t num_vals;
915 if (remaining < 10) {
916 errno = EIO;
917 goto failed;
919 len = strnlen((char *)p, remaining - 6);
920 if (len == remaining - 6) {
921 errno = EIO;
922 goto failed;
924 name = talloc_strndup(tmp_ctx, (char *)p, len);
925 if (name == NULL) {
926 errno = ENOMEM;
927 goto failed;
929 remaining -= len + 1;
930 p += len + 1;
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;
940 } else if (num_vals != 1) {
941 errno = EIO;
942 goto failed;
945 p += 4;
946 remaining -= 4;
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;
955 val = talloc_strndup(tmp_ctx, (char *)(p + 4), len);
956 if (val == NULL) {
957 errno = ENOMEM;
958 goto failed;
961 remaining -= len+4+1;
962 p += len+4+1;
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;
972 } else if (strcasecmp_m(name, "sid") == 0) {
973 if (!string_to_sid(&map->sid, val)) {
974 errno = EIO;
975 goto failed;
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;
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;
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;
995 } else if (strcasecmp_m(name, "member") == 0) {
996 if (!string_to_sid(&members[j], val)) {
997 errno = EIO;
998 goto failed;
1002 TALLOC_FREE(val);
1005 TALLOC_FREE(name);
1008 if (map->nt_name == NULL) {
1009 errno = EIO;
1010 goto failed;
1013 if (map->comment == NULL) {
1014 map->comment = talloc_strdup(map, "");
1016 if (map->comment == NULL) {
1017 errno = ENOMEM;
1018 goto failed;
1021 if (!add_mapping_entry(map, 0)) {
1022 errno = EIO;
1023 goto failed;
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;
1037 if (remaining != 0) {
1038 DEBUG(0, ("Errror: %d bytes unread in ltdb_unpack_data\n",
1039 remaining));
1042 TALLOC_FREE(map);
1043 return 0;
1045 failed:
1046 TALLOC_FREE(map);
1047 return -1;
1050 static bool mapping_switch(const char *ldb_path)
1052 TDB_CONTEXT *ltdb;
1053 TALLOC_CTX *frame;
1054 char *new_path;
1055 int ret;
1057 frame = talloc_stackframe();
1059 ltdb = tdb_open_log(ldb_path, 0, TDB_DEFAULT, O_RDONLY, 0600);
1060 if (ltdb == NULL) goto failed;
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;
1067 if (ltdb) {
1068 tdb_close(ltdb);
1069 ltdb = NULL;
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;
1077 if (rename(ldb_path, new_path) != 0) {
1078 DEBUG(0,("Failed to rename old group mapping database\n"));
1079 goto failed;
1081 TALLOC_FREE(frame);
1082 return True;
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;
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
1105 initialise the tdb mapping backend
1107 const struct mapping_backend *groupdb_tdb_init(void)
1109 if (!init_group_mapping()) {
1110 DEBUG(0,("Failed to initialise tdb mapping backend\n"));
1111 return NULL;
1114 return &tdb_backend;