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