1/*
2 * Unix SMB/CIFS implementation.
3 * SMB parameters and setup
4 * Copyright (C) Andrew Tridgell   1992-1998
5 * Copyright (C) Simo Sorce        2000-2003
6 * Copyright (C) Gerald Carter     2000
7 * Copyright (C) Jeremy Allison    2001
8 * Copyright (C) Andrew Bartlett   2002
9 *
10 * This program is free software; you can redistribute it and/or modify it under
11 * the terms of the GNU General Public License as published by the Free
12 * Software Foundation; either version 2 of the License, or (at your option)
13 * any later version.
14 *
15 * This program is distributed in the hope that it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
18 * more details.
19 *
20 * You should have received a copy of the GNU General Public License along with
21 * this program; if not, write to the Free Software Foundation, Inc., 675
22 * Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25#include "includes.h"
26
27#if 0 /* when made a module use this */
28
29static int tdbsam_debug_level = DBGC_ALL;
30#undef DBGC_CLASS
31#define DBGC_CLASS tdbsam_debug_level
32
33#else
34
35#undef DBGC_CLASS
36#define DBGC_CLASS DBGC_PASSDB
37
38#endif
39
40#define TDBSAM_VERSION	2	/* Most recent TDBSAM version */
41#define TDBSAM_VERSION_STRING	"INFO/version"
42#define PASSDB_FILE_NAME	"passdb.tdb"
43#define USERPREFIX		"USER_"
44#define RIDPREFIX		"RID_"
45#define PRIVPREFIX		"PRIV_"
46#define tdbsamver_t 	int32
47
48struct tdbsam_privates {
49	TDB_CONTEXT 	*passwd_tdb;
50
51	/* retrive-once info */
52	const char *tdbsam_location;
53};
54
55struct pwent_list {
56	struct pwent_list *prev, *next;
57	TDB_DATA key;
58};
59static struct pwent_list *tdbsam_pwent_list;
60
61
62/**
63 * Convert old TDBSAM to the latest version.
64 * @param pdb_tdb A pointer to the opened TDBSAM file which must be converted.
65 *                This file must be opened with read/write access.
66 * @param from Current version of the TDBSAM file.
67 * @return True if the conversion has been successful, false otherwise.
68 **/
69
70static BOOL tdbsam_convert(TDB_CONTEXT *pdb_tdb, tdbsamver_t from)
71{
72	const char * vstring = TDBSAM_VERSION_STRING;
73	SAM_ACCOUNT *user = NULL;
74	const char *prefix = USERPREFIX;
75	TDB_DATA 	data, key, old_key;
76	uint8		*buf = NULL;
77	BOOL 		ret;
78
79	if (pdb_tdb == NULL) {
80		DEBUG(0,("tdbsam_convert: Bad TDB Context pointer.\n"));
81		return False;
82	}
83
84	/* handle a Samba upgrade */
85	tdb_lock_bystring(pdb_tdb, vstring, 0);
86
87	if (!NT_STATUS_IS_OK(pdb_init_sam(&user))) {
88		DEBUG(0,("tdbsam_convert: cannot initialized a SAM_ACCOUNT.\n"));
89		return False;
90	}
91
92	/* Enumerate all records and convert them */
93	key = tdb_firstkey(pdb_tdb);
94
95	while (key.dptr) {
96
97		/* skip all non-USER entries (eg. RIDs) */
98		while ((key.dsize != 0) && (strncmp(key.dptr, prefix, strlen (prefix)))) {
99			old_key = key;
100			/* increment to next in line */
101			key = tdb_nextkey(pdb_tdb, key);
102			SAFE_FREE(old_key.dptr);
103		}
104
105		if (key.dptr) {
106
107			/* read from tdbsam */
108			data = tdb_fetch(pdb_tdb, key);
109			if (!data.dptr) {
110				DEBUG(0,("tdbsam_convert: database entry not found: %s.\n",key.dptr));
111				return False;
112			}
113
114			if (!NT_STATUS_IS_OK(pdb_reset_sam(user))) {
115				DEBUG(0,("tdbsam_convert: cannot reset SAM_ACCOUNT.\n"));
116				SAFE_FREE(data.dptr);
117				return False;
118			}
119
120			/* unpack the buffer from the former format */
121			DEBUG(10,("tdbsam_convert: Try unpacking a record with (key:%s) (version:%d)\n", key.dptr, from));
122			switch (from) {
123				case 0:
124					ret = init_sam_from_buffer_v0(user, (uint8 *)data.dptr, data.dsize);
125					break;
126				case 1:
127					ret = init_sam_from_buffer_v1(user, (uint8 *)data.dptr, data.dsize);
128					break;
129				case 2:
130					ret = init_sam_from_buffer_v2(user, (uint8 *)data.dptr, data.dsize);
131					break;
132				default:
133					/* unknown tdbsam version */
134					ret = False;
135			}
136			if (!ret) {
137				DEBUG(0,("tdbsam_convert: Bad SAM_ACCOUNT entry returned from TDB (key:%s) (version:%d)\n", key.dptr, from));
138				SAFE_FREE(data.dptr);
139				return False;
140			}
141
142			/* We're finished with the old data. */
143			SAFE_FREE(data.dptr);
144
145			/* pack from the buffer into the new format */
146			DEBUG(10,("tdbsam_convert: Try packing a record (key:%s) (version:%d)\n", key.dptr, from));
147			if ((data.dsize=init_buffer_from_sam (&buf, user, False)) == -1) {
148				DEBUG(0,("tdbsam_convert: cannot pack the SAM_ACCOUNT into the new format\n"));
149				SAFE_FREE(data.dptr);
150				return False;
151			}
152			data.dptr = (char *)buf;
153
154			/* Store the buffer inside the TDBSAM */
155			if (tdb_store(pdb_tdb, key, data, TDB_MODIFY) != TDB_SUCCESS) {
156				DEBUG(0,("tdbsam_convert: cannot store the SAM_ACCOUNT (key:%s) in new format\n",key.dptr));
157				SAFE_FREE(data.dptr);
158				return False;
159			}
160
161			SAFE_FREE(data.dptr);
162
163			/* increment to next in line */
164			old_key = key;
165			key = tdb_nextkey(pdb_tdb, key);
166			SAFE_FREE(old_key.dptr);
167		}
168
169	}
170
171	pdb_free_sam(&user);
172
173	/* upgrade finished */
174	tdb_store_int32(pdb_tdb, vstring, TDBSAM_VERSION);
175	tdb_unlock_bystring(pdb_tdb, vstring);
176
177	return(True);
178}
179
180/**
181 * Open the TDB passwd database, check version and convert it if needed.
182 * @param name filename of the tdbsam file.
183 * @param open_flags file access mode.
184 * @return a TDB_CONTEXT handle on the tdbsam file.
185 **/
186
187static TDB_CONTEXT * tdbsam_tdbopen (const char *name, int open_flags)
188{
189	TDB_CONTEXT 	*pdb_tdb;
190	tdbsamver_t	version;
191
192	/* Try to open tdb passwd */
193	if (!(pdb_tdb = tdb_open_log(name, 0, TDB_DEFAULT,
194				     open_flags, 0600))) {
195		DEBUG(0, ("Unable to open/create TDB passwd\n"));
196		return NULL;
197	}
198
199	/* Check the version */
200	version = (tdbsamver_t) tdb_fetch_int32(pdb_tdb,
201						TDBSAM_VERSION_STRING);
202	if (version == -1)
203		version = 0;	/* Version not found, assume version 0 */
204
205	/* Compare the version */
206	if (version > TDBSAM_VERSION) {
207		/* Version more recent than the latest known */
208		DEBUG(0, ("TDBSAM version unknown: %d\n", version));
209		tdb_close(pdb_tdb);
210		pdb_tdb = NULL;
211	}
212	else if (version < TDBSAM_VERSION) {
213		/* Older version, must be converted */
214		DEBUG(1, ("TDBSAM version too old (%d), trying to convert it.\n", version));
215
216		/* Reopen the pdb file with read-write access if needed */
217		if (!(open_flags & O_RDWR)) {
218			DEBUG(10, ("tdbsam_tdbopen: TDB file opened with read only access, reopen it with read-write access.\n"));
219			tdb_close(pdb_tdb);
220			pdb_tdb = tdb_open_log(name, 0, TDB_DEFAULT, (open_flags & 07777770) | O_RDWR, 0600);
221		}
222
223		/* Convert */
224		if (!tdbsam_convert(pdb_tdb, version)){
225			DEBUG(0, ("tdbsam_tdbopen: Error when trying to convert tdbsam: %s\n",name));
226			tdb_close(pdb_tdb);
227			pdb_tdb = NULL;
228		} else {
229			DEBUG(1, ("TDBSAM converted successfully.\n"));
230		}
231
232		/* Reopen the pdb file as it must be */
233		if (!(open_flags & O_RDWR)) {
234			tdb_close(pdb_tdb);
235			pdb_tdb = tdb_open_log(name, 0, TDB_DEFAULT, open_flags, 0600);
236		}
237	}
238
239	return pdb_tdb;
240}
241
242/*****************************************************************************
243 Utility functions to close the tdb sam database
244 ****************************************************************************/
245
246static void tdbsam_tdbclose ( struct tdbsam_privates *state )
247{
248	if ( !state )
249		return;
250
251	if ( state->passwd_tdb ) {
252		tdb_close( state->passwd_tdb );
253		state->passwd_tdb = NULL;
254	}
255
256	return;
257
258}
259
260/****************************************************************************
261 creates a list of user keys
262****************************************************************************/
263
264static int tdbsam_traverse_setpwent(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void *state)
265{
266	const char *prefix = USERPREFIX;
267	int  prefixlen = strlen (prefix);
268	struct pwent_list *ptr;
269
270	if ( strncmp(key.dptr, prefix, prefixlen) == 0 ) {
271		if ( !(ptr=SMB_MALLOC_P(struct pwent_list)) ) {
272			DEBUG(0,("tdbsam_traverse_setpwent: Failed to malloc new entry for list\n"));
273
274			/* just return 0 and let the traversal continue */
275			return 0;
276		}
277		ZERO_STRUCTP(ptr);
278
279		/* save a copy of the key */
280
281		ptr->key.dptr = memdup( key.dptr, key.dsize );
282		ptr->key.dsize = key.dsize;
283
284		DLIST_ADD( tdbsam_pwent_list, ptr );
285
286	}
287
288
289	return 0;
290}
291
292/***************************************************************
293 Open the TDB passwd database for SAM account enumeration.
294 Save a list of user keys for iteration.
295****************************************************************/
296
297static NTSTATUS tdbsam_setsampwent(struct pdb_methods *my_methods, BOOL update, uint16 acb_mask)
298{
299	uint32 flags = update ? (O_RDWR|O_CREAT) : O_RDONLY;
300
301	struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)my_methods->private_data;
302
303	if ( !(tdb_state->passwd_tdb = tdbsam_tdbopen(tdb_state->tdbsam_location, flags )) )
304		return NT_STATUS_UNSUCCESSFUL;
305
306	tdb_traverse( tdb_state->passwd_tdb, tdbsam_traverse_setpwent, NULL );
307
308	return NT_STATUS_OK;
309}
310
311
312/***************************************************************
313 End enumeration of the TDB passwd list.
314****************************************************************/
315
316static void tdbsam_endsampwent(struct pdb_methods *my_methods)
317{
318	struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)my_methods->private_data;
319	struct pwent_list *ptr, *ptr_next;
320
321	tdbsam_tdbclose( tdb_state );
322
323	/* clear out any remaining entries in the list */
324
325	for ( ptr=tdbsam_pwent_list; ptr; ptr = ptr_next ) {
326		ptr_next = ptr->next;
327		DLIST_REMOVE( tdbsam_pwent_list, ptr );
328		SAFE_FREE( ptr->key.dptr);
329		SAFE_FREE( ptr );
330	}
331
332	DEBUG(7, ("endtdbpwent: closed sam database.\n"));
333}
334
335/*****************************************************************
336 Get one SAM_ACCOUNT from the TDB (next in line)
337*****************************************************************/
338
339static NTSTATUS tdbsam_getsampwent(struct pdb_methods *my_methods, SAM_ACCOUNT *user)
340{
341	NTSTATUS 		nt_status = NT_STATUS_UNSUCCESSFUL;
342	struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)my_methods->private_data;
343	TDB_DATA 		data;
344	struct pwent_list	*pkey;
345
346	if ( !user ) {
347		DEBUG(0,("tdbsam_getsampwent: SAM_ACCOUNT is NULL.\n"));
348		return nt_status;
349	}
350
351	if ( !tdbsam_pwent_list ) {
352		DEBUG(4,("tdbsam_getsampwent: end of list\n"));
353		tdbsam_tdbclose( tdb_state );
354		return nt_status;
355	}
356
357	if ( !tdb_state->passwd_tdb ) {
358		if ( !(tdb_state->passwd_tdb = tdbsam_tdbopen(tdb_state->tdbsam_location, O_RDONLY)) )
359			return nt_status;
360	}
361
362	/* pull the next entry */
363
364	pkey = tdbsam_pwent_list;
365	DLIST_REMOVE( tdbsam_pwent_list, pkey );
366
367	data = tdb_fetch(tdb_state->passwd_tdb, pkey->key);
368
369	SAFE_FREE( pkey->key.dptr);
370	SAFE_FREE( pkey);
371
372	if (!data.dptr) {
373		DEBUG(5,("pdb_getsampwent: database entry not found.  Was the user deleted?\n"));
374		return nt_status;
375	}
376
377	if (!init_sam_from_buffer(user, (unsigned char *)data.dptr, data.dsize)) {
378		DEBUG(0,("pdb_getsampwent: Bad SAM_ACCOUNT entry returned from TDB!\n"));
379	}
380
381	SAFE_FREE( data.dptr );
382
383
384	return NT_STATUS_OK;
385}
386
387/******************************************************************
388 Lookup a name in the SAM TDB
389******************************************************************/
390
391static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods, SAM_ACCOUNT *user, const char *sname)
392{
393	NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
394	struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)my_methods->private_data;
395	TDB_CONTEXT 	*pwd_tdb;
396	TDB_DATA 	data, key;
397	fstring 	keystr;
398	fstring		name;
399
400	if ( !user ) {
401		DEBUG(0,("pdb_getsampwnam: SAM_ACCOUNT is NULL.\n"));
402		return nt_status;
403	}
404
405	/* Data is stored in all lower-case */
406	fstrcpy(name, sname);
407	strlower_m(name);
408
409	/* set search key */
410	slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
411	key.dptr = keystr;
412	key.dsize = strlen(keystr) + 1;
413
414	/* open the accounts TDB */
415	if (!(pwd_tdb = tdbsam_tdbopen(tdb_state->tdbsam_location, O_RDONLY))) {
416
417		if (errno == ENOENT) {
418			/*
419			 * TDB file doesn't exist, so try to create new one. This is useful to avoid
420			 * confusing error msg when adding user account first time
421			 */
422			if (!(pwd_tdb = tdbsam_tdbopen(tdb_state->tdbsam_location, O_CREAT ))) {
423				DEBUG(0, ("pdb_getsampwnam: TDB passwd (%s) did not exist. File successfully created.\n",
424				          tdb_state->tdbsam_location));
425			} else {
426				DEBUG(0, ("pdb_getsampwnam: TDB passwd (%s) does not exist. Couldn't create new one. Error was: %s\n",
427				          tdb_state->tdbsam_location, strerror(errno)));
428			}
429
430			/* requested user isn't there anyway */
431			nt_status = NT_STATUS_NO_SUCH_USER;
432			return nt_status;
433		}
434		DEBUG(0, ("pdb_getsampwnam: Unable to open TDB passwd (%s)!\n", tdb_state->tdbsam_location));
435		return nt_status;
436	}
437
438	/* get the record */
439	data = tdb_fetch(pwd_tdb, key);
440	if (!data.dptr) {
441		DEBUG(5,("pdb_getsampwnam (TDB): error fetching database.\n"));
442		DEBUGADD(5, (" Error: %s\n", tdb_errorstr(pwd_tdb)));
443		DEBUGADD(5, (" Key: %s\n", keystr));
444		tdb_close(pwd_tdb);
445		return nt_status;
446	}
447
448  	/* unpack the buffer */
449	if (!init_sam_from_buffer(user, (unsigned char *)data.dptr, data.dsize)) {
450		DEBUG(0,("pdb_getsampwent: Bad SAM_ACCOUNT entry returned from TDB!\n"));
451		SAFE_FREE(data.dptr);
452		tdb_close(pwd_tdb);
453		return nt_status;
454	}
455	SAFE_FREE(data.dptr);
456
457	/* no further use for database, close it now */
458	tdb_close(pwd_tdb);
459
460	return NT_STATUS_OK;
461}
462
463/***************************************************************************
464 Search by rid
465 **************************************************************************/
466
467static NTSTATUS tdbsam_getsampwrid (struct pdb_methods *my_methods, SAM_ACCOUNT *user, uint32 rid)
468{
469	NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
470	struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)my_methods->private_data;
471	TDB_CONTEXT 		*pwd_tdb;
472	TDB_DATA 		data, key;
473	fstring 		keystr;
474	fstring			name;
475
476	if (user==NULL) {
477		DEBUG(0,("pdb_getsampwrid: SAM_ACCOUNT is NULL.\n"));
478		return nt_status;
479	}
480
481	/* set search key */
482	slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
483	key.dptr = keystr;
484	key.dsize = strlen (keystr) + 1;
485
486	/* open the accounts TDB */
487	if (!(pwd_tdb = tdbsam_tdbopen(tdb_state->tdbsam_location, O_RDONLY))) {
488		DEBUG(0, ("pdb_getsampwrid: Unable to open TDB rid database!\n"));
489		return nt_status;
490	}
491
492	/* get the record */
493	data = tdb_fetch (pwd_tdb, key);
494	if (!data.dptr) {
495		DEBUG(5,("pdb_getsampwrid (TDB): error looking up RID %d by key %s.\n", rid, keystr));
496		DEBUGADD(5, (" Error: %s\n", tdb_errorstr(pwd_tdb)));
497		tdb_close (pwd_tdb);
498		return nt_status;
499	}
500
501
502	fstrcpy(name, data.dptr);
503	SAFE_FREE(data.dptr);
504
505	tdb_close (pwd_tdb);
506
507	return tdbsam_getsampwnam (my_methods, user, name);
508}
509
510static NTSTATUS tdbsam_getsampwsid(struct pdb_methods *my_methods, SAM_ACCOUNT * user, const DOM_SID *sid)
511{
512	uint32 rid;
513	if (!sid_peek_check_rid(get_global_sam_sid(), sid, &rid))
514		return NT_STATUS_UNSUCCESSFUL;
515	return tdbsam_getsampwrid(my_methods, user, rid);
516}
517
518/***************************************************************************
519 Delete a SAM_ACCOUNT
520****************************************************************************/
521
522static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods, SAM_ACCOUNT *sam_pass)
523{
524	NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
525	struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)my_methods->private_data;
526	TDB_CONTEXT 	*pwd_tdb;
527	TDB_DATA 	key;
528	fstring 	keystr;
529	uint32		rid;
530	fstring		name;
531
532	fstrcpy(name, pdb_get_username(sam_pass));
533	strlower_m(name);
534
535	/* open the TDB */
536	if (!(pwd_tdb = tdbsam_tdbopen(tdb_state->tdbsam_location, O_RDWR))) {
537		DEBUG(0, ("Unable to open TDB passwd!"));
538		return nt_status;
539	}
540
541  	/* set the search key */
542	slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
543	key.dptr = keystr;
544	key.dsize = strlen (keystr) + 1;
545
546	rid = pdb_get_user_rid(sam_pass);
547
548	/* it's outaa here!  8^) */
549	if (tdb_delete(pwd_tdb, key) != TDB_SUCCESS) {
550		DEBUG(5, ("Error deleting entry from tdb passwd database!\n"));
551		DEBUGADD(5, (" Error: %s\n", tdb_errorstr(pwd_tdb)));
552		tdb_close(pwd_tdb);
553		return nt_status;
554	}
555
556	/* delete also the RID key */
557
558  	/* set the search key */
559	slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
560	key.dptr = keystr;
561	key.dsize = strlen (keystr) + 1;
562
563	/* it's outaa here!  8^) */
564	if (tdb_delete(pwd_tdb, key) != TDB_SUCCESS) {
565		DEBUG(5, ("Error deleting entry from tdb rid database!\n"));
566		DEBUGADD(5, (" Error: %s\n", tdb_errorstr(pwd_tdb)));
567		tdb_close(pwd_tdb);
568		return nt_status;
569	}
570
571	tdb_close(pwd_tdb);
572
573	return NT_STATUS_OK;
574}
575
576/***************************************************************************
577 Update the TDB SAM
578****************************************************************************/
579
580static BOOL tdb_update_sam(struct pdb_methods *my_methods, SAM_ACCOUNT* newpwd, int flag)
581{
582	struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)my_methods->private_data;
583	TDB_CONTEXT 	*pwd_tdb = NULL;
584	TDB_DATA 	key, data;
585	uint8		*buf = NULL;
586	fstring 	keystr;
587	fstring		name;
588	BOOL		ret = True;
589	uint32		user_rid;
590
591	/* invalidate the existing TDB iterator if it is open */
592
593	if (tdb_state->passwd_tdb) {
594		tdb_close(tdb_state->passwd_tdb);
595		tdb_state->passwd_tdb = NULL;
596	}
597
598 	/* open the account TDB passwd*/
599
600	pwd_tdb = tdbsam_tdbopen(tdb_state->tdbsam_location, O_RDWR | O_CREAT);
601
602  	if (!pwd_tdb) {
603		DEBUG(0, ("tdb_update_sam: Unable to open TDB passwd (%s)!\n",
604			tdb_state->tdbsam_location));
605		return False;
606	}
607
608	if (!pdb_get_group_rid(newpwd)) {
609		DEBUG (0,("tdb_update_sam: Failing to store a SAM_ACCOUNT for [%s] without a primary group RID\n",
610			pdb_get_username(newpwd)));
611		ret = False;
612		goto done;
613	}
614
615	if ( !(user_rid = pdb_get_user_rid(newpwd)) ) {
616		DEBUG(0,("tdb_update_sam: SAM_ACCOUNT (%s) with no RID!\n", pdb_get_username(newpwd)));
617		ret = False;
618		goto done;
619	}
620
621	/* copy the SAM_ACCOUNT struct into a BYTE buffer for storage */
622	if ((data.dsize=init_buffer_from_sam (&buf, newpwd, False)) == -1) {
623		DEBUG(0,("tdb_update_sam: ERROR - Unable to copy SAM_ACCOUNT info BYTE buffer!\n"));
624		ret = False;
625		goto done;
626	}
627	data.dptr = (char *)buf;
628
629	fstrcpy(name, pdb_get_username(newpwd));
630	strlower_m(name);
631
632	DEBUG(5, ("Storing %saccount %s with RID %d\n", flag == TDB_INSERT ? "(new) " : "", name, user_rid));
633
634  	/* setup the USER index key */
635	slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
636	key.dptr = keystr;
637	key.dsize = strlen(keystr) + 1;
638
639	/* add the account */
640	if (tdb_store(pwd_tdb, key, data, flag) != TDB_SUCCESS) {
641		DEBUG(0, ("Unable to modify passwd TDB!"));
642		DEBUGADD(0, (" Error: %s", tdb_errorstr(pwd_tdb)));
643		DEBUGADD(0, (" occured while storing the main record (%s)\n", keystr));
644		ret = False;
645		goto done;
646	}
647
648	/* setup RID data */
649	data.dsize = strlen(name) + 1;
650	data.dptr = name;
651
652	/* setup the RID index key */
653	slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, user_rid);
654	key.dptr = keystr;
655	key.dsize = strlen (keystr) + 1;
656
657	/* add the reference */
658	if (tdb_store(pwd_tdb, key, data, flag) != TDB_SUCCESS) {
659		DEBUG(0, ("Unable to modify TDB passwd !"));
660		DEBUGADD(0, (" Error: %s\n", tdb_errorstr(pwd_tdb)));
661		DEBUGADD(0, (" occured while storing the RID index (%s)\n", keystr));
662		ret = False;
663		goto done;
664	}
665
666done:
667	/* cleanup */
668	tdb_close (pwd_tdb);
669	SAFE_FREE(buf);
670
671	return (ret);
672}
673
674/***************************************************************************
675 Modifies an existing SAM_ACCOUNT
676****************************************************************************/
677
678static NTSTATUS tdbsam_update_sam_account (struct pdb_methods *my_methods, SAM_ACCOUNT *newpwd)
679{
680	if (tdb_update_sam(my_methods, newpwd, TDB_MODIFY))
681		return NT_STATUS_OK;
682	else
683		return NT_STATUS_UNSUCCESSFUL;
684}
685
686/***************************************************************************
687 Adds an existing SAM_ACCOUNT
688****************************************************************************/
689
690static NTSTATUS tdbsam_add_sam_account (struct pdb_methods *my_methods, SAM_ACCOUNT *newpwd)
691{
692	if (tdb_update_sam(my_methods, newpwd, TDB_INSERT))
693		return NT_STATUS_OK;
694	else
695		return NT_STATUS_UNSUCCESSFUL;
696}
697
698static void free_private_data(void **vp)
699{
700	struct tdbsam_privates **tdb_state = (struct tdbsam_privates **)vp;
701	tdbsam_tdbclose(*tdb_state);
702	*tdb_state = NULL;
703
704	/* No need to free any further, as it is talloc()ed */
705}
706
707
708
709
710/**
711 * Init tdbsam backend
712 *
713 * @param pdb_context initialised passdb context
714 * @param pdb_method backend methods structure to be filled with function pointers
715 * @param location the backend tdb file location
716 *
717 * @return nt_status code
718 **/
719
720static NTSTATUS pdb_init_tdbsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location)
721{
722	NTSTATUS nt_status;
723	struct tdbsam_privates *tdb_state;
724
725	if (!NT_STATUS_IS_OK(nt_status = make_pdb_methods(pdb_context->mem_ctx, pdb_method))) {
726		return nt_status;
727	}
728
729	(*pdb_method)->name = "tdbsam";
730
731	(*pdb_method)->setsampwent = tdbsam_setsampwent;
732	(*pdb_method)->endsampwent = tdbsam_endsampwent;
733	(*pdb_method)->getsampwent = tdbsam_getsampwent;
734	(*pdb_method)->getsampwnam = tdbsam_getsampwnam;
735	(*pdb_method)->getsampwsid = tdbsam_getsampwsid;
736	(*pdb_method)->add_sam_account = tdbsam_add_sam_account;
737	(*pdb_method)->update_sam_account = tdbsam_update_sam_account;
738	(*pdb_method)->delete_sam_account = tdbsam_delete_sam_account;
739
740	tdb_state = TALLOC_ZERO_P(pdb_context->mem_ctx, struct tdbsam_privates);
741
742	if (!tdb_state) {
743		DEBUG(0, ("talloc() failed for tdbsam private_data!\n"));
744		return NT_STATUS_NO_MEMORY;
745	}
746
747	if (location) {
748		tdb_state->tdbsam_location = talloc_strdup(pdb_context->mem_ctx, location);
749	} else {
750		pstring tdbfile;
751		get_private_directory(tdbfile);
752		pstrcat(tdbfile, "/");
753		pstrcat(tdbfile, PASSDB_FILE_NAME);
754		tdb_state->tdbsam_location = talloc_strdup(pdb_context->mem_ctx, tdbfile);
755	}
756
757	(*pdb_method)->private_data = tdb_state;
758
759	(*pdb_method)->free_private_data = free_private_data;
760
761	return NT_STATUS_OK;
762}
763
764NTSTATUS pdb_tdbsam_init(void)
765{
766	return smb_register_passdb(PASSDB_INTERFACE_VERSION, "tdbsam", pdb_init_tdbsam);
767}
768