s3: only include tdb headers where needed.
[sfrench/samba-autobuild/.git] / source3 / passdb / pdb_tdb.c
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-2006
7  * Copyright (C) Jeremy Allison    2001-2009
8  * Copyright (C) Andrew Bartlett   2002
9  * Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2005
10  * 
11  * This program is free software; you can redistribute it and/or modify it under
12  * the terms of the GNU General Public License as published by the Free
13  * Software Foundation; either version 3 of the License, or (at your option)
14  * any later version.
15  * 
16  * This program is distributed in the hope that it will be useful, but WITHOUT
17  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
19  * more details.
20  * 
21  * You should have received a copy of the GNU General Public License along with
22  * this program; if not, see <http://www.gnu.org/licenses/>.
23  */
24
25 #include "includes.h"
26 #include "system/filesys.h"
27 #include "passdb.h"
28 #include "dbwrap.h"
29 #include "../libcli/security/security.h"
30 #include "util_tdb.h"
31
32 #if 0 /* when made a module use this */
33
34 static int tdbsam_debug_level = DBGC_ALL;
35 #undef DBGC_CLASS
36 #define DBGC_CLASS tdbsam_debug_level
37
38 #else
39
40 #undef DBGC_CLASS
41 #define DBGC_CLASS DBGC_PASSDB
42
43 #endif
44
45 #define TDBSAM_VERSION  4       /* Most recent TDBSAM version */
46 #define TDBSAM_MINOR_VERSION    0       /* Most recent TDBSAM minor version */
47 #define TDBSAM_VERSION_STRING   "INFO/version"
48 #define TDBSAM_MINOR_VERSION_STRING     "INFO/minor_version"
49 #define PASSDB_FILE_NAME        "passdb.tdb"
50 #define USERPREFIX              "USER_"
51 #define USERPREFIX_LEN          5
52 #define RIDPREFIX               "RID_"
53 #define PRIVPREFIX              "PRIV_"
54 #define NEXT_RID_STRING         "NEXT_RID"
55
56 /* GLOBAL TDB SAM CONTEXT */
57
58 static struct db_context *db_sam;
59 static char *tdbsam_filename;
60
61 struct tdbsam_convert_state {
62         int32_t from;
63         bool success;
64 };
65
66 static int tdbsam_convert_one(struct db_record *rec, void *priv)
67 {
68         struct tdbsam_convert_state *state =
69                 (struct tdbsam_convert_state *)priv;
70         struct samu *user;
71         TDB_DATA data;
72         NTSTATUS status;
73         bool ret;
74
75         if (rec->key.dsize < USERPREFIX_LEN) {
76                 return 0;
77         }
78         if (strncmp((char *)rec->key.dptr, USERPREFIX, USERPREFIX_LEN) != 0) {
79                 return 0;
80         }
81
82         user = samu_new(talloc_tos());
83         if (user == NULL) {
84                 DEBUG(0,("tdbsam_convert: samu_new() failed!\n"));
85                 state->success = false;
86                 return -1;
87         }
88
89         DEBUG(10,("tdbsam_convert: Try unpacking a record with (key:%s) "
90                   "(version:%d)\n", rec->key.dptr, state->from));
91
92         switch (state->from) {
93         case 0:
94                 ret = init_samu_from_buffer(user, SAMU_BUFFER_V0,
95                                             (uint8 *)rec->value.dptr,
96                                             rec->value.dsize);
97                 break;
98         case 1:
99                 ret = init_samu_from_buffer(user, SAMU_BUFFER_V1,
100                                             (uint8 *)rec->value.dptr,
101                                             rec->value.dsize);
102                 break;
103         case 2:
104                 ret = init_samu_from_buffer(user, SAMU_BUFFER_V2,
105                                             (uint8 *)rec->value.dptr,
106                                             rec->value.dsize);
107                 break;
108         case 3:
109                 ret = init_samu_from_buffer(user, SAMU_BUFFER_V3,
110                                             (uint8 *)rec->value.dptr,
111                                             rec->value.dsize);
112                 break;
113         case 4:
114                 ret = init_samu_from_buffer(user, SAMU_BUFFER_V4,
115                                             (uint8 *)rec->value.dptr,
116                                             rec->value.dsize);
117                 break;
118         default:
119                 /* unknown tdbsam version */
120                 ret = False;
121         }
122         if (!ret) {
123                 DEBUG(0,("tdbsam_convert: Bad struct samu entry returned "
124                          "from TDB (key:%s) (version:%d)\n", rec->key.dptr,
125                          state->from));
126                 TALLOC_FREE(user);
127                 state->success = false;
128                 return -1;
129         }
130
131         data.dsize = init_buffer_from_samu(&data.dptr, user, false);
132         TALLOC_FREE(user);
133
134         if (data.dsize == -1) {
135                 DEBUG(0,("tdbsam_convert: cannot pack the struct samu into "
136                          "the new format\n"));
137                 state->success = false;
138                 return -1;
139         }
140
141         status = rec->store(rec, data, TDB_MODIFY);
142         if (!NT_STATUS_IS_OK(status)) {
143                 DEBUG(0, ("Could not store the new record: %s\n",
144                           nt_errstr(status)));
145                 state->success = false;
146                 return -1;
147         }
148
149         return 0;
150 }
151
152 /**********************************************************************
153  Struct and function to backup an old record.
154  *********************************************************************/
155
156 struct tdbsam_backup_state {
157         struct db_context *new_db;
158         bool success;
159 };
160
161 static int backup_copy_fn(struct db_record *orig_rec, void *state)
162 {
163         struct tdbsam_backup_state *bs = (struct tdbsam_backup_state *)state;
164         struct db_record *new_rec;
165         NTSTATUS status;
166
167         new_rec = bs->new_db->fetch_locked(bs->new_db, talloc_tos(), orig_rec->key);
168         if (new_rec == NULL) {
169                 bs->success = false;
170                 return 1;
171         }
172
173         status = new_rec->store(new_rec, orig_rec->value, TDB_INSERT);
174
175         TALLOC_FREE(new_rec);
176
177         if (!NT_STATUS_IS_OK(status)) {
178                 bs->success = false;
179                 return 1;
180         }
181         return 0;
182 }
183
184 /**********************************************************************
185  Make a backup of an old passdb and replace the new one with it. We
186  have to do this as between 3.0.x and 3.2.x the hash function changed
187  by mistake (used unsigned char * instead of char *). This means the
188  previous simple update code will fail due to not being able to find
189  existing records to replace in the tdbsam_convert_one() function. JRA.
190  *********************************************************************/
191
192 static bool tdbsam_convert_backup(const char *dbname, struct db_context **pp_db)
193 {
194         TALLOC_CTX *frame = talloc_stackframe();
195         const char *tmp_fname = NULL;
196         struct db_context *tmp_db = NULL;
197         struct db_context *orig_db = *pp_db;
198         struct tdbsam_backup_state bs;
199         int ret;
200
201         tmp_fname = talloc_asprintf(frame, "%s.tmp", dbname);
202         if (!tmp_fname) {
203                 TALLOC_FREE(frame);
204                 return false;
205         }
206
207         unlink(tmp_fname);
208
209         /* Remember to open this on the NULL context. We need
210          * it to stay around after we return from here. */
211
212         tmp_db = db_open(NULL, tmp_fname, 0,
213                                 TDB_DEFAULT, O_CREAT|O_RDWR, 0600);
214         if (tmp_db == NULL) {
215                 DEBUG(0, ("tdbsam_convert_backup: Failed to create backup TDB passwd "
216                           "[%s]\n", tmp_fname));
217                 TALLOC_FREE(frame);
218                 return false;
219         }
220
221         if (orig_db->transaction_start(orig_db) != 0) {
222                 DEBUG(0, ("tdbsam_convert_backup: Could not start transaction (1)\n"));
223                 unlink(tmp_fname);
224                 TALLOC_FREE(tmp_db);
225                 TALLOC_FREE(frame);
226                 return false;
227         }
228         if (tmp_db->transaction_start(tmp_db) != 0) {
229                 DEBUG(0, ("tdbsam_convert_backup: Could not start transaction (2)\n"));
230                 orig_db->transaction_cancel(orig_db);
231                 unlink(tmp_fname);
232                 TALLOC_FREE(tmp_db);
233                 TALLOC_FREE(frame);
234                 return false;
235         }
236
237         bs.new_db = tmp_db;
238         bs.success = true;
239
240         ret = orig_db->traverse(orig_db, backup_copy_fn, (void *)&bs);
241         if (ret < 0) {
242                 DEBUG(0, ("tdbsam_convert_backup: traverse failed\n"));
243                 goto cancel;
244         }
245
246         if (!bs.success) {
247                 DEBUG(0, ("tdbsam_convert_backup: Rewriting records failed\n"));
248                 goto cancel;
249         }
250
251         if (orig_db->transaction_commit(orig_db) != 0) {
252                 smb_panic("tdbsam_convert_backup: orig commit failed\n");
253         }
254         if (tmp_db->transaction_commit(tmp_db) != 0) {
255                 smb_panic("tdbsam_convert_backup: orig commit failed\n");
256         }
257
258         /* be sure to close the DBs _before_ renaming the file */
259
260         TALLOC_FREE(orig_db);
261         TALLOC_FREE(tmp_db);
262
263         /* This is safe from other users as we know we're
264          * under a mutex here. */
265
266         if (rename(tmp_fname, dbname) == -1) {
267                 DEBUG(0, ("tdbsam_convert_backup: rename of %s to %s failed %s\n",
268                         tmp_fname,
269                         dbname,
270                         strerror(errno)));
271                 smb_panic("tdbsam_convert_backup: replace passdb failed\n");
272         }
273
274         TALLOC_FREE(frame);
275
276         /* re-open the converted TDB */
277
278         orig_db = db_open(NULL, dbname, 0,
279                           TDB_DEFAULT, O_CREAT|O_RDWR, 0600);
280         if (orig_db == NULL) {
281                 DEBUG(0, ("tdbsam_convert_backup: Failed to re-open "
282                           "converted passdb TDB [%s]\n", dbname));
283                 return false;
284         }
285
286         DEBUG(1, ("tdbsam_convert_backup: updated %s file.\n",
287                 dbname ));
288
289         /* Replace the global db pointer. */
290         *pp_db = orig_db;
291         return true;
292
293   cancel:
294
295         if (orig_db->transaction_cancel(orig_db) != 0) {
296                 smb_panic("tdbsam_convert: transaction_cancel failed");
297         }
298
299         if (tmp_db->transaction_cancel(tmp_db) != 0) {
300                 smb_panic("tdbsam_convert: transaction_cancel failed");
301         }
302
303         unlink(tmp_fname);
304         TALLOC_FREE(tmp_db);
305         TALLOC_FREE(frame);
306         return false;
307 }
308
309 static bool tdbsam_upgrade_next_rid(struct db_context *db)
310 {
311         TDB_CONTEXT *tdb;
312         uint32 rid;
313         bool ok = false;
314
315         ok = dbwrap_fetch_uint32(db, NEXT_RID_STRING, &rid);
316         if (ok) {
317                 return true;
318         }
319
320         tdb = tdb_open_log(state_path("winbindd_idmap.tdb"), 0,
321                            TDB_DEFAULT, O_RDONLY, 0644);
322
323         if (tdb) {
324                 ok = tdb_fetch_uint32(tdb, "RID_COUNTER", &rid);
325                 if (!ok) {
326                         rid = BASE_RID;
327                 }
328                 tdb_close(tdb);
329         } else {
330                 rid = BASE_RID;
331         }
332
333         if (dbwrap_store_uint32(db, NEXT_RID_STRING, rid) != 0) {
334                 return false;
335         }
336
337         return true;
338 }
339
340 static bool tdbsam_convert(struct db_context **pp_db, const char *name, int32 from)
341 {
342         struct tdbsam_convert_state state;
343         struct db_context *db = NULL;
344         int ret;
345
346         /* We only need the update backup for local db's. */
347         if (db_is_local(name) && !tdbsam_convert_backup(name, pp_db)) {
348                 DEBUG(0, ("tdbsam_convert: Could not backup %s\n", name));
349                 return false;
350         }
351
352         db = *pp_db;
353         state.from = from;
354         state.success = true;
355
356         if (db->transaction_start(db) != 0) {
357                 DEBUG(0, ("tdbsam_convert: Could not start transaction\n"));
358                 return false;
359         }
360
361         if (!tdbsam_upgrade_next_rid(db)) {
362                 DEBUG(0, ("tdbsam_convert: tdbsam_upgrade_next_rid failed\n"));
363                 goto cancel;
364         }
365
366         ret = db->traverse(db, tdbsam_convert_one, &state);
367         if (ret < 0) {
368                 DEBUG(0, ("tdbsam_convert: traverse failed\n"));
369                 goto cancel;
370         }
371
372         if (!state.success) {
373                 DEBUG(0, ("tdbsam_convert: Converting records failed\n"));
374                 goto cancel;
375         }
376
377         if (dbwrap_store_int32(db, TDBSAM_VERSION_STRING,
378                                TDBSAM_VERSION) != 0) {
379                 DEBUG(0, ("tdbsam_convert: Could not store tdbsam version\n"));
380                 goto cancel;
381         }
382
383         if (dbwrap_store_int32(db, TDBSAM_MINOR_VERSION_STRING,
384                                TDBSAM_MINOR_VERSION) != 0) {
385                 DEBUG(0, ("tdbsam_convert: Could not store tdbsam minor version\n"));
386                 goto cancel;
387         }
388
389         if (db->transaction_commit(db) != 0) {
390                 DEBUG(0, ("tdbsam_convert: Could not commit transaction\n"));
391                 return false;
392         }
393
394         return true;
395
396  cancel:
397         if (db->transaction_cancel(db) != 0) {
398                 smb_panic("tdbsam_convert: transaction_cancel failed");
399         }
400
401         return false;
402 }
403
404 /*********************************************************************
405  Open the tdbsam file based on the absolute path specified.
406  Uses a reference count to allow multiple open calls.
407 *********************************************************************/
408
409 static bool tdbsam_open( const char *name )
410 {
411         int32   version;
412         int32   minor_version;
413
414         /* check if we are already open */
415
416         if ( db_sam ) {
417                 return true;
418         }
419
420         /* Try to open tdb passwd.  Create a new one if necessary */
421
422         db_sam = db_open(NULL, name, 0, TDB_DEFAULT, O_CREAT|O_RDWR, 0600);
423         if (db_sam == NULL) {
424                 DEBUG(0, ("tdbsam_open: Failed to open/create TDB passwd "
425                           "[%s]\n", name));
426                 return false;
427         }
428
429         /* Check the version */
430         version = dbwrap_fetch_int32(db_sam, TDBSAM_VERSION_STRING);
431         if (version == -1) {
432                 version = 0;    /* Version not found, assume version 0 */
433         }
434
435         /* Get the minor version */
436         minor_version = dbwrap_fetch_int32(db_sam, TDBSAM_MINOR_VERSION_STRING);
437         if (minor_version == -1) {
438                 minor_version = 0; /* Minor version not found, assume 0 */
439         }
440
441         /* Compare the version */
442         if (version > TDBSAM_VERSION) {
443                 /* Version more recent than the latest known */
444                 DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
445                 TALLOC_FREE(db_sam);
446                 return false;
447         }
448
449         if ( version < TDBSAM_VERSION ||
450                         (version == TDBSAM_VERSION &&
451                          minor_version < TDBSAM_MINOR_VERSION) ) {
452                 /*
453                  * Ok - we think we're going to have to convert.
454                  * Due to the backup process we now must do to
455                  * upgrade we have to get a mutex and re-check
456                  * the version. Someone else may have upgraded
457                  * whilst we were checking.
458                  */
459
460                 struct named_mutex *mtx = grab_named_mutex(NULL,
461                                                 "tdbsam_upgrade_mutex",
462                                                 600);
463
464                 if (!mtx) {
465                         DEBUG(0, ("tdbsam_open: failed to grab mutex.\n"));
466                         TALLOC_FREE(db_sam);
467                         return false;
468                 }
469
470                 /* Re-check the version */
471                 version = dbwrap_fetch_int32(db_sam, TDBSAM_VERSION_STRING);
472                 if (version == -1) {
473                         version = 0;    /* Version not found, assume version 0 */
474                 }
475
476                 /* Re-check the minor version */
477                 minor_version = dbwrap_fetch_int32(db_sam, TDBSAM_MINOR_VERSION_STRING);
478                 if (minor_version == -1) {
479                         minor_version = 0; /* Minor version not found, assume 0 */
480                 }
481
482                 /* Compare the version */
483                 if (version > TDBSAM_VERSION) {
484                         /* Version more recent than the latest known */
485                         DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
486                         TALLOC_FREE(db_sam);
487                         TALLOC_FREE(mtx);
488                         return false;
489                 }
490
491                 if ( version < TDBSAM_VERSION ||
492                                 (version == TDBSAM_VERSION &&
493                                  minor_version < TDBSAM_MINOR_VERSION) ) {
494                         /*
495                          * Note that minor versions we read that are greater
496                          * than the current minor version we have hard coded
497                          * are assumed to be compatible if they have the same
498                          * major version. That allows previous versions of the
499                          * passdb code that don't know about minor versions to
500                          * still use this database. JRA.
501                          */
502
503                         DEBUG(1, ("tdbsam_open: Converting version %d.%d database to "
504                                   "version %d.%d.\n",
505                                         version,
506                                         minor_version,
507                                         TDBSAM_VERSION,
508                                         TDBSAM_MINOR_VERSION));
509
510                         if ( !tdbsam_convert(&db_sam, name, version) ) {
511                                 DEBUG(0, ("tdbsam_open: Error when trying to convert "
512                                           "tdbsam [%s]\n",name));
513                                 TALLOC_FREE(db_sam);
514                                 TALLOC_FREE(mtx);
515                                 return false;
516                         }
517
518                         DEBUG(3, ("TDBSAM converted successfully.\n"));
519                 }
520                 TALLOC_FREE(mtx);
521         }
522
523         DEBUG(4,("tdbsam_open: successfully opened %s\n", name ));
524
525         return true;
526 }
527
528 /******************************************************************
529  Lookup a name in the SAM TDB
530 ******************************************************************/
531
532 static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods,
533                                     struct samu *user, const char *sname)
534 {
535         TDB_DATA        data;
536         fstring         keystr;
537         fstring         name;
538
539         if ( !user ) {
540                 DEBUG(0,("pdb_getsampwnam: struct samu is NULL.\n"));
541                 return NT_STATUS_NO_MEMORY;
542         }
543
544         /* Data is stored in all lower-case */
545         fstrcpy(name, sname);
546         strlower_m(name);
547
548         /* set search key */
549         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
550
551         /* open the database */
552
553         if ( !tdbsam_open( tdbsam_filename ) ) {
554                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
555                 return NT_STATUS_ACCESS_DENIED;
556         }
557
558         /* get the record */
559
560         data = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr);
561         if (!data.dptr) {
562                 DEBUG(5,("pdb_getsampwnam (TDB): error fetching database.\n"));
563                 DEBUGADD(5, (" Key: %s\n", keystr));
564                 return NT_STATUS_NO_SUCH_USER;
565         }
566
567         /* unpack the buffer */
568
569         if (!init_samu_from_buffer(user, SAMU_BUFFER_LATEST, data.dptr, data.dsize)) {
570                 DEBUG(0,("pdb_getsampwent: Bad struct samu entry returned from TDB!\n"));
571                 SAFE_FREE(data.dptr);
572                 return NT_STATUS_NO_MEMORY;
573         }
574
575         /* success */
576
577         TALLOC_FREE(data.dptr);
578
579         return NT_STATUS_OK;
580 }
581
582 /***************************************************************************
583  Search by rid
584  **************************************************************************/
585
586 static NTSTATUS tdbsam_getsampwrid (struct pdb_methods *my_methods,
587                                     struct samu *user, uint32 rid)
588 {
589         NTSTATUS                nt_status = NT_STATUS_UNSUCCESSFUL;
590         TDB_DATA                data;
591         fstring                 keystr;
592         fstring                 name;
593
594         if ( !user ) {
595                 DEBUG(0,("pdb_getsampwrid: struct samu is NULL.\n"));
596                 return nt_status;
597         }
598
599         /* set search key */
600
601         slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
602
603         /* open the database */
604
605         if ( !tdbsam_open( tdbsam_filename ) ) {
606                 DEBUG(0,("tdbsam_getsampwrid: failed to open %s!\n", tdbsam_filename));
607                 return NT_STATUS_ACCESS_DENIED;
608         }
609
610         /* get the record */
611
612         data = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr);
613         if (!data.dptr) {
614                 DEBUG(5,("pdb_getsampwrid (TDB): error looking up RID %d by key %s.\n", rid, keystr));
615                 return NT_STATUS_UNSUCCESSFUL;
616         }
617
618         fstrcpy(name, (const char *)data.dptr);
619         TALLOC_FREE(data.dptr);
620
621         return tdbsam_getsampwnam (my_methods, user, name);
622 }
623
624 static NTSTATUS tdbsam_getsampwsid(struct pdb_methods *my_methods,
625                                    struct samu * user, const struct dom_sid *sid)
626 {
627         uint32 rid;
628
629         if ( !sid_peek_check_rid(get_global_sam_sid(), sid, &rid) )
630                 return NT_STATUS_UNSUCCESSFUL;
631
632         return tdbsam_getsampwrid(my_methods, user, rid);
633 }
634
635 static bool tdb_delete_samacct_only( struct samu *sam_pass )
636 {
637         fstring         keystr;
638         fstring         name;
639         NTSTATUS status;
640
641         fstrcpy(name, pdb_get_username(sam_pass));
642         strlower_m(name);
643
644         /* set the search key */
645
646         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
647
648         /* it's outaa here!  8^) */
649         if ( !tdbsam_open( tdbsam_filename ) ) {
650                 DEBUG(0,("tdb_delete_samacct_only: failed to open %s!\n",
651                          tdbsam_filename));
652                 return false;
653         }
654
655         status = dbwrap_delete_bystring(db_sam, keystr);
656         if (!NT_STATUS_IS_OK(status)) {
657                 DEBUG(5, ("Error deleting entry from tdb passwd "
658                           "database: %s!\n", nt_errstr(status)));
659                 return false;
660         }
661
662         return true;
663 }
664
665 /***************************************************************************
666  Delete a struct samu records for the username and RID key
667 ****************************************************************************/
668
669 static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods,
670                                           struct samu *sam_pass)
671 {
672         NTSTATUS        nt_status = NT_STATUS_UNSUCCESSFUL;
673         fstring         keystr;
674         uint32          rid;
675         fstring         name;
676
677         /* open the database */
678
679         if ( !tdbsam_open( tdbsam_filename ) ) {
680                 DEBUG(0,("tdbsam_delete_sam_account: failed to open %s!\n",
681                          tdbsam_filename));
682                 return NT_STATUS_ACCESS_DENIED;
683         }
684
685         fstrcpy(name, pdb_get_username(sam_pass));
686         strlower_m(name);
687
688         /* set the search key */
689
690         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
691
692         rid = pdb_get_user_rid(sam_pass);
693
694         /* it's outaa here!  8^) */
695
696         if (db_sam->transaction_start(db_sam) != 0) {
697                 DEBUG(0, ("Could not start transaction\n"));
698                 return NT_STATUS_UNSUCCESSFUL;
699         }
700
701         nt_status = dbwrap_delete_bystring(db_sam, keystr);
702         if (!NT_STATUS_IS_OK(nt_status)) {
703                 DEBUG(5, ("Error deleting entry from tdb passwd "
704                           "database: %s!\n", nt_errstr(nt_status)));
705                 goto cancel;
706         }
707
708         /* set the search key */
709
710         slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
711
712         /* it's outaa here!  8^) */
713
714         nt_status = dbwrap_delete_bystring(db_sam, keystr);
715         if (!NT_STATUS_IS_OK(nt_status)) {
716                 DEBUG(5, ("Error deleting entry from tdb rid "
717                           "database: %s!\n", nt_errstr(nt_status)));
718                 goto cancel;
719         }
720
721         if (db_sam->transaction_commit(db_sam) != 0) {
722                 DEBUG(0, ("Could not commit transaction\n"));
723                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
724         }
725
726         return NT_STATUS_OK;
727
728  cancel:
729         if (db_sam->transaction_cancel(db_sam) != 0) {
730                 smb_panic("transaction_cancel failed");
731         }
732
733         return nt_status;
734 }
735
736
737 /***************************************************************************
738  Update the TDB SAM account record only
739  Assumes that the tdbsam is already open 
740 ****************************************************************************/
741 static bool tdb_update_samacct_only( struct samu* newpwd, int flag )
742 {
743         TDB_DATA        data;
744         uint8           *buf = NULL;
745         fstring         keystr;
746         fstring         name;
747         bool            ret = false;
748         NTSTATUS status;
749
750         /* copy the struct samu struct into a BYTE buffer for storage */
751
752         if ( (data.dsize=init_buffer_from_samu(&buf, newpwd, False)) == -1 ) {
753                 DEBUG(0,("tdb_update_sam: ERROR - Unable to copy struct samu info BYTE buffer!\n"));
754                 goto done;
755         }
756         data.dptr = buf;
757
758         fstrcpy(name, pdb_get_username(newpwd));
759         strlower_m(name);
760
761         DEBUG(5, ("Storing %saccount %s with RID %d\n",
762                   flag == TDB_INSERT ? "(new) " : "", name,
763                   pdb_get_user_rid(newpwd)));
764
765         /* setup the USER index key */
766         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
767
768         /* add the account */
769
770         status = dbwrap_store_bystring(db_sam, keystr, data, flag);
771         if (!NT_STATUS_IS_OK(status)) {
772                 DEBUG(0, ("Unable to modify passwd TDB: %s!",
773                           nt_errstr(status)));
774                 goto done;
775         }
776
777         ret = true;
778
779 done:
780         /* cleanup */
781         SAFE_FREE(buf);
782         return ret;
783 }
784
785 /***************************************************************************
786  Update the TDB SAM RID record only
787  Assumes that the tdbsam is already open
788 ****************************************************************************/
789 static bool tdb_update_ridrec_only( struct samu* newpwd, int flag )
790 {
791         TDB_DATA        data;
792         fstring         keystr;
793         fstring         name;
794         NTSTATUS status;
795
796         fstrcpy(name, pdb_get_username(newpwd));
797         strlower_m(name);
798
799         /* setup RID data */
800         data = string_term_tdb_data(name);
801
802         /* setup the RID index key */
803         slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX,
804                  pdb_get_user_rid(newpwd));
805
806         /* add the reference */
807         status = dbwrap_store_bystring(db_sam, keystr, data, flag);
808         if (!NT_STATUS_IS_OK(status)) {
809                 DEBUG(0, ("Unable to modify TDB passwd: %s!\n",
810                           nt_errstr(status)));
811                 return false;
812         }
813
814         return true;
815
816 }
817
818 /***************************************************************************
819  Update the TDB SAM
820 ****************************************************************************/
821
822 static bool tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd,
823                            int flag)
824 {
825         uint32_t oldrid;
826         uint32_t newrid;
827
828         if (!(newrid = pdb_get_user_rid(newpwd))) {
829                 DEBUG(0,("tdb_update_sam: struct samu (%s) with no RID!\n",
830                          pdb_get_username(newpwd)));
831                 return False;
832         }
833
834         oldrid = newrid;
835
836         /* open the database */
837
838         if ( !tdbsam_open( tdbsam_filename ) ) {
839                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
840                 return False;
841         }
842
843         if (db_sam->transaction_start(db_sam) != 0) {
844                 DEBUG(0, ("Could not start transaction\n"));
845                 return false;
846         }
847
848         /* If we are updating, we may be changing this users RID. Retrieve the old RID
849            so we can check. */
850
851         if (flag == TDB_MODIFY) {
852                 struct samu *account = samu_new(talloc_tos());
853                 if (account == NULL) {
854                         DEBUG(0,("tdb_update_sam: samu_new() failed\n"));
855                         goto cancel;
856                 }
857                 if (!NT_STATUS_IS_OK(tdbsam_getsampwnam(my_methods, account, pdb_get_username(newpwd)))) {
858                         DEBUG(0,("tdb_update_sam: tdbsam_getsampwnam() for %s failed\n",
859                                 pdb_get_username(newpwd)));
860                         TALLOC_FREE(account);
861                         goto cancel;
862                 }
863                 if (!(oldrid = pdb_get_user_rid(account))) {
864                         DEBUG(0,("tdb_update_sam: pdb_get_user_rid() failed\n"));
865                         TALLOC_FREE(account);
866                         goto cancel;
867                 }
868                 TALLOC_FREE(account);
869         }
870
871         /* Update the new samu entry. */
872         if (!tdb_update_samacct_only(newpwd, flag)) {
873                 goto cancel;
874         }
875
876         /* Now take care of the case where the RID changed. We need
877          * to delete the old RID key and add the new. */
878
879         if (flag == TDB_MODIFY && newrid != oldrid) { 
880                 fstring keystr;
881
882                 /* Delete old RID key */
883                 DEBUG(10, ("tdb_update_sam: Deleting key for RID %u\n", oldrid));
884                 slprintf(keystr, sizeof(keystr) - 1, "%s%.8x", RIDPREFIX, oldrid);
885                 if (!NT_STATUS_IS_OK(dbwrap_delete_bystring(db_sam, keystr))) {
886                         DEBUG(0, ("tdb_update_sam: Can't delete %s\n", keystr));
887                         goto cancel;
888                 }
889                 /* Insert new RID key */
890                 DEBUG(10, ("tdb_update_sam: Inserting key for RID %u\n", newrid));
891                 if (!tdb_update_ridrec_only(newpwd, TDB_INSERT)) {
892                         goto cancel;
893                 }
894         } else {
895                 DEBUG(10, ("tdb_update_sam: %s key for RID %u\n",
896                         flag == TDB_MODIFY ? "Updating" : "Inserting", newrid));
897                 if (!tdb_update_ridrec_only(newpwd, flag)) {
898                         goto cancel;
899                 }
900         }
901
902         if (db_sam->transaction_commit(db_sam) != 0) {
903                 DEBUG(0, ("Could not commit transaction\n"));
904                 return false;
905         }
906
907         return true;
908
909  cancel:
910         if (db_sam->transaction_cancel(db_sam) != 0) {
911                 smb_panic("transaction_cancel failed");
912         }
913         return false;
914 }
915
916 /***************************************************************************
917  Modifies an existing struct samu
918 ****************************************************************************/
919
920 static NTSTATUS tdbsam_update_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
921 {
922         if ( !tdb_update_sam(my_methods, newpwd, TDB_MODIFY) )
923                 return NT_STATUS_UNSUCCESSFUL;
924         
925         return NT_STATUS_OK;
926 }
927
928 /***************************************************************************
929  Adds an existing struct samu
930 ****************************************************************************/
931
932 static NTSTATUS tdbsam_add_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
933 {
934         if ( !tdb_update_sam(my_methods, newpwd, TDB_INSERT) )
935                 return NT_STATUS_UNSUCCESSFUL;
936                 
937         return NT_STATUS_OK;
938 }
939
940 /***************************************************************************
941  Renames a struct samu
942  - check for the posix user/rename user script
943  - Add and lock the new user record
944  - rename the posix user
945  - rewrite the rid->username record
946  - delete the old user
947  - unlock the new user record
948 ***************************************************************************/
949 static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
950                                           struct samu *old_acct,
951                                           const char *newname)
952 {
953         struct samu      *new_acct = NULL;
954         char *rename_script = NULL;
955         int              rename_ret;
956         fstring          oldname_lower;
957         fstring          newname_lower;
958
959         /* can't do anything without an external script */
960
961         if ( !(new_acct = samu_new( talloc_tos() )) ) {
962                 return NT_STATUS_NO_MEMORY;
963         }
964
965         rename_script = talloc_strdup(new_acct, lp_renameuser_script());
966         if (!rename_script) {
967                 TALLOC_FREE(new_acct);
968                 return NT_STATUS_NO_MEMORY;
969         }
970         if (!*rename_script) {
971                 TALLOC_FREE(new_acct);
972                 return NT_STATUS_ACCESS_DENIED;
973         }
974
975         if ( !pdb_copy_sam_account(new_acct, old_acct)
976                 || !pdb_set_username(new_acct, newname, PDB_CHANGED))
977         {
978                 TALLOC_FREE(new_acct);
979                 return NT_STATUS_NO_MEMORY;
980         }
981
982         /* open the database */
983         if ( !tdbsam_open( tdbsam_filename ) ) {
984                 DEBUG(0, ("tdbsam_getsampwnam: failed to open %s!\n",
985                           tdbsam_filename));
986                 TALLOC_FREE(new_acct);
987                 return NT_STATUS_ACCESS_DENIED;
988         }
989
990         if (db_sam->transaction_start(db_sam) != 0) {
991                 DEBUG(0, ("Could not start transaction\n"));
992                 TALLOC_FREE(new_acct);
993                 return NT_STATUS_ACCESS_DENIED;
994
995         }
996
997         /* add the new account and lock it */
998         if ( !tdb_update_samacct_only(new_acct, TDB_INSERT) ) {
999                 goto cancel;
1000         }
1001
1002         /* Rename the posix user.  Follow the semantics of _samr_create_user()
1003            so that we lower case the posix name but preserve the case in passdb */
1004
1005         fstrcpy( oldname_lower, pdb_get_username(old_acct) );
1006         strlower_m( oldname_lower );
1007
1008         fstrcpy( newname_lower, newname );
1009         strlower_m( newname_lower );
1010
1011         rename_script = talloc_string_sub2(new_acct,
1012                                 rename_script,
1013                                 "%unew",
1014                                 newname_lower,
1015                                 true,
1016                                 false,
1017                                 true);
1018         if (!rename_script) {
1019                 goto cancel;
1020         }
1021         rename_script = talloc_string_sub2(new_acct,
1022                                 rename_script,
1023                                 "%uold",
1024                                 oldname_lower,
1025                                 true,
1026                                 false,
1027                                 true);
1028         if (!rename_script) {
1029                 goto cancel;
1030         }
1031         rename_ret = smbrun(rename_script, NULL);
1032
1033         DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n",
1034                                 rename_script, rename_ret));
1035
1036         if (rename_ret != 0) {
1037                 goto cancel;
1038         }
1039
1040         smb_nscd_flush_user_cache();
1041
1042         /* rewrite the rid->username record */
1043
1044         if ( !tdb_update_ridrec_only( new_acct, TDB_MODIFY) ) {
1045                 goto cancel;
1046         }
1047
1048         tdb_delete_samacct_only( old_acct );
1049
1050         if (db_sam->transaction_commit(db_sam) != 0) {
1051                 /*
1052                  * Ok, we're screwed. We've changed the posix account, but
1053                  * could not adapt passdb.tdb. Shall we change the posix
1054                  * account back?
1055                  */
1056                 DEBUG(0, ("transaction_commit failed\n"));
1057                 TALLOC_FREE(new_acct);
1058                 return NT_STATUS_INTERNAL_DB_CORRUPTION;        
1059         }
1060
1061         TALLOC_FREE(new_acct );
1062         return NT_STATUS_OK;
1063
1064  cancel:
1065         if (db_sam->transaction_cancel(db_sam) != 0) {
1066                 smb_panic("transaction_cancel failed");
1067         }
1068
1069         TALLOC_FREE(new_acct);
1070
1071         return NT_STATUS_ACCESS_DENIED; 
1072 }
1073
1074 static uint32_t tdbsam_capabilities(struct pdb_methods *methods)
1075 {
1076         return PDB_CAP_STORE_RIDS;
1077 }
1078
1079 static bool tdbsam_new_rid(struct pdb_methods *methods, uint32 *prid)
1080 {
1081         uint32 rid;
1082         NTSTATUS status;
1083
1084         rid = BASE_RID;         /* Default if not set */
1085
1086         if (!tdbsam_open(tdbsam_filename)) {
1087                 DEBUG(0,("tdbsam_new_rid: failed to open %s!\n",
1088                         tdbsam_filename));
1089                 return false;
1090         }
1091
1092         status = dbwrap_trans_change_uint32_atomic(db_sam, NEXT_RID_STRING,
1093                                                    &rid, 1);
1094         if (!NT_STATUS_IS_OK(status)) {
1095                 DEBUG(3, ("tdbsam_new_rid: Failed to increase %s: %s\n",
1096                         NEXT_RID_STRING, nt_errstr(status)));
1097                 return false;
1098         }
1099
1100         *prid = rid;
1101
1102         return true;
1103 }
1104
1105 struct tdbsam_search_state {
1106         struct pdb_methods *methods;
1107         uint32_t acct_flags;
1108
1109         uint32_t *rids;
1110         uint32_t num_rids;
1111         ssize_t array_size;
1112         uint32_t current;
1113 };
1114
1115 static int tdbsam_collect_rids(struct db_record *rec, void *private_data)
1116 {
1117         struct tdbsam_search_state *state = talloc_get_type_abort(
1118                 private_data, struct tdbsam_search_state);
1119         size_t prefixlen = strlen(RIDPREFIX);
1120         uint32 rid;
1121
1122         if ((rec->key.dsize < prefixlen)
1123             || (strncmp((char *)rec->key.dptr, RIDPREFIX, prefixlen))) {
1124                 return 0;
1125         }
1126
1127         rid = strtoul((char *)rec->key.dptr+prefixlen, NULL, 16);
1128
1129         ADD_TO_LARGE_ARRAY(state, uint32, rid, &state->rids, &state->num_rids,
1130                            &state->array_size);
1131
1132         return 0;
1133 }
1134
1135 static void tdbsam_search_end(struct pdb_search *search)
1136 {
1137         struct tdbsam_search_state *state = talloc_get_type_abort(
1138                 search->private_data, struct tdbsam_search_state);
1139         TALLOC_FREE(state);
1140 }
1141
1142 static bool tdbsam_search_next_entry(struct pdb_search *search,
1143                                      struct samr_displayentry *entry)
1144 {
1145         struct tdbsam_search_state *state = talloc_get_type_abort(
1146                 search->private_data, struct tdbsam_search_state);
1147         struct samu *user = NULL;
1148         NTSTATUS status;
1149         uint32_t rid;
1150
1151  again:
1152         TALLOC_FREE(user);
1153         user = samu_new(talloc_tos());
1154         if (user == NULL) {
1155                 DEBUG(0, ("samu_new failed\n"));
1156                 return false;
1157         }
1158
1159         if (state->current == state->num_rids) {
1160                 return false;
1161         }
1162
1163         rid = state->rids[state->current++];
1164
1165         status = tdbsam_getsampwrid(state->methods, user, rid);
1166
1167         if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
1168                 /*
1169                  * Someone has deleted that user since we listed the RIDs
1170                  */
1171                 goto again;
1172         }
1173
1174         if (!NT_STATUS_IS_OK(status)) {
1175                 DEBUG(10, ("tdbsam_getsampwrid failed: %s\n",
1176                            nt_errstr(status)));
1177                 TALLOC_FREE(user);
1178                 return false;
1179         }
1180
1181         if ((state->acct_flags != 0) &&
1182             ((state->acct_flags & pdb_get_acct_ctrl(user)) == 0)) {
1183                 goto again;
1184         }
1185
1186         entry->acct_flags = pdb_get_acct_ctrl(user);
1187         entry->rid = rid;
1188         entry->account_name = talloc_strdup(search, pdb_get_username(user));
1189         entry->fullname = talloc_strdup(search, pdb_get_fullname(user));
1190         entry->description = talloc_strdup(search, pdb_get_acct_desc(user));
1191
1192         TALLOC_FREE(user);
1193
1194         if ((entry->account_name == NULL) || (entry->fullname == NULL)
1195             || (entry->description == NULL)) {
1196                 DEBUG(0, ("talloc_strdup failed\n"));
1197                 return false;
1198         }
1199
1200         return true;
1201 }
1202
1203 static bool tdbsam_search_users(struct pdb_methods *methods,
1204                                 struct pdb_search *search,
1205                                 uint32 acct_flags)
1206 {
1207         struct tdbsam_search_state *state;
1208
1209         if (!tdbsam_open(tdbsam_filename)) {
1210                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n",
1211                          tdbsam_filename));
1212                 return false;
1213         }
1214
1215         state = talloc_zero(search, struct tdbsam_search_state);
1216         if (state == NULL) {
1217                 DEBUG(0, ("talloc failed\n"));
1218                 return false;
1219         }
1220         state->acct_flags = acct_flags;
1221         state->methods = methods;
1222
1223         db_sam->traverse_read(db_sam, tdbsam_collect_rids, state);
1224
1225         search->private_data = state;
1226         search->next_entry = tdbsam_search_next_entry;
1227         search->search_end = tdbsam_search_end;
1228
1229         return true;
1230 }
1231
1232 /*********************************************************************
1233  Initialize the tdb sam backend.  Setup the dispath table of methods,
1234  open the tdb, etc...
1235 *********************************************************************/
1236
1237 static NTSTATUS pdb_init_tdbsam(struct pdb_methods **pdb_method, const char *location)
1238 {
1239         NTSTATUS nt_status;
1240         char *tdbfile = NULL;
1241         const char *pfile = location;
1242
1243         if (!NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method ))) {
1244                 return nt_status;
1245         }
1246
1247         (*pdb_method)->name = "tdbsam";
1248
1249         (*pdb_method)->getsampwnam = tdbsam_getsampwnam;
1250         (*pdb_method)->getsampwsid = tdbsam_getsampwsid;
1251         (*pdb_method)->add_sam_account = tdbsam_add_sam_account;
1252         (*pdb_method)->update_sam_account = tdbsam_update_sam_account;
1253         (*pdb_method)->delete_sam_account = tdbsam_delete_sam_account;
1254         (*pdb_method)->rename_sam_account = tdbsam_rename_sam_account;
1255         (*pdb_method)->search_users = tdbsam_search_users;
1256
1257         (*pdb_method)->capabilities = tdbsam_capabilities;
1258         (*pdb_method)->new_rid = tdbsam_new_rid;
1259
1260         /* save the path for later */
1261
1262         if (!location) {
1263                 if (asprintf(&tdbfile, "%s/%s", lp_private_dir(),
1264                              PASSDB_FILE_NAME) < 0) {
1265                         return NT_STATUS_NO_MEMORY;
1266                 }
1267                 pfile = tdbfile;
1268         }
1269         tdbsam_filename = SMB_STRDUP(pfile);
1270         if (!tdbsam_filename) {
1271                 return NT_STATUS_NO_MEMORY;
1272         }
1273         SAFE_FREE(tdbfile);
1274
1275         /* no private data */
1276
1277         (*pdb_method)->private_data      = NULL;
1278         (*pdb_method)->free_private_data = NULL;
1279
1280         return NT_STATUS_OK;
1281 }
1282
1283 NTSTATUS pdb_tdbsam_init(void)
1284 {
1285         return smb_register_passdb(PASSDB_INTERFACE_VERSION, "tdbsam", pdb_init_tdbsam);
1286 }