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