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