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