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