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