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