Allow pdbedit to change a user rid/sid. Based on a fix from Alexander Zagrebin <alexz...
[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         uint32_t oldrid;
821         uint32_t newrid;
822
823         if (!(newrid = pdb_get_user_rid(newpwd))) {
824                 DEBUG(0,("tdb_update_sam: struct samu (%s) with no RID!\n",
825                          pdb_get_username(newpwd)));
826                 return False;
827         }
828
829         oldrid = newrid;
830
831         /* open the database */
832
833         if ( !tdbsam_open( tdbsam_filename ) ) {
834                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
835                 return False;
836         }
837
838         if (db_sam->transaction_start(db_sam) != 0) {
839                 DEBUG(0, ("Could not start transaction\n"));
840                 return false;
841         }
842
843         /* If we are updating, we may be changing this users RID. Retrieve the old RID
844            so we can check. */
845
846         if (flag == TDB_MODIFY) {
847                 struct samu *account = samu_new(talloc_tos());
848                 if (account == NULL) {
849                         DEBUG(0,("tdb_update_sam: samu_new() failed\n"));
850                         goto cancel;
851                 }
852                 if (!NT_STATUS_IS_OK(tdbsam_getsampwnam(my_methods, account, pdb_get_username(newpwd)))) {
853                         DEBUG(0,("tdb_update_sam: tdbsam_getsampwnam() for %s failed\n",
854                                 pdb_get_username(newpwd)));
855                         TALLOC_FREE(account);
856                         goto cancel;
857                 }
858                 if (!(oldrid = pdb_get_user_rid(account))) {
859                         DEBUG(0,("tdb_update_sam: pdb_get_user_rid() failed\n"));
860                         TALLOC_FREE(account);
861                         goto cancel;
862                 }
863                 TALLOC_FREE(account);
864         }
865
866         /* Update the new samu entry. */
867         if (!tdb_update_samacct_only(newpwd, flag)) {
868                 goto cancel;
869         }
870
871         /* Now take care of the case where the RID changed. We need
872          * to delete the old RID key and add the new. */
873
874         if (flag == TDB_MODIFY && newrid != oldrid) { 
875                 fstring keystr;
876
877                 /* Delete old RID key */
878                 DEBUG(10, ("tdb_update_sam: Deleting key for RID %u\n", oldrid));
879                 slprintf(keystr, sizeof(keystr) - 1, "%s%.8x", RIDPREFIX, oldrid);
880                 if (!NT_STATUS_IS_OK(dbwrap_delete_bystring(db_sam, keystr))) {
881                         DEBUG(0, ("tdb_update_sam: Can't delete %s\n", keystr));
882                         goto cancel;
883                 }
884                 /* Insert new RID key */
885                 DEBUG(10, ("tdb_update_sam: Inserting key for RID %u\n", newrid));
886                 if (!tdb_update_ridrec_only(newpwd, TDB_INSERT)) {
887                         goto cancel;
888                 }
889         } else {
890                 DEBUG(10, ("tdb_update_sam: %s key for RID %u\n",
891                         flag == TDB_MODIFY ? "Updating" : "Inserting", newrid));
892                 if (!tdb_update_ridrec_only(newpwd, flag)) {
893                         goto cancel;
894                 }
895         }
896
897         if (db_sam->transaction_commit(db_sam) != 0) {
898                 DEBUG(0, ("Could not commit transaction\n"));
899                 return false;
900         }
901
902         return true;
903
904  cancel:
905         if (db_sam->transaction_cancel(db_sam) != 0) {
906                 smb_panic("transaction_cancel failed");
907         }
908         return false;
909 }
910
911 /***************************************************************************
912  Modifies an existing struct samu
913 ****************************************************************************/
914
915 static NTSTATUS tdbsam_update_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
916 {
917         if ( !tdb_update_sam(my_methods, newpwd, TDB_MODIFY) )
918                 return NT_STATUS_UNSUCCESSFUL;
919         
920         return NT_STATUS_OK;
921 }
922
923 /***************************************************************************
924  Adds an existing struct samu
925 ****************************************************************************/
926
927 static NTSTATUS tdbsam_add_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
928 {
929         if ( !tdb_update_sam(my_methods, newpwd, TDB_INSERT) )
930                 return NT_STATUS_UNSUCCESSFUL;
931                 
932         return NT_STATUS_OK;
933 }
934
935 /***************************************************************************
936  Renames a struct samu
937  - check for the posix user/rename user script
938  - Add and lock the new user record
939  - rename the posix user
940  - rewrite the rid->username record
941  - delete the old user
942  - unlock the new user record
943 ***************************************************************************/
944 static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
945                                           struct samu *old_acct,
946                                           const char *newname)
947 {
948         struct samu      *new_acct = NULL;
949         char *rename_script = NULL;
950         int              rename_ret;
951         fstring          oldname_lower;
952         fstring          newname_lower;
953
954         /* can't do anything without an external script */
955
956         if ( !(new_acct = samu_new( talloc_tos() )) ) {
957                 return NT_STATUS_NO_MEMORY;
958         }
959
960         rename_script = talloc_strdup(new_acct, lp_renameuser_script());
961         if (!rename_script) {
962                 TALLOC_FREE(new_acct);
963                 return NT_STATUS_NO_MEMORY;
964         }
965         if (!*rename_script) {
966                 TALLOC_FREE(new_acct);
967                 return NT_STATUS_ACCESS_DENIED;
968         }
969
970         if ( !pdb_copy_sam_account(new_acct, old_acct)
971                 || !pdb_set_username(new_acct, newname, PDB_CHANGED))
972         {
973                 TALLOC_FREE(new_acct);
974                 return NT_STATUS_NO_MEMORY;
975         }
976
977         /* open the database */
978         if ( !tdbsam_open( tdbsam_filename ) ) {
979                 DEBUG(0, ("tdbsam_getsampwnam: failed to open %s!\n",
980                           tdbsam_filename));
981                 TALLOC_FREE(new_acct);
982                 return NT_STATUS_ACCESS_DENIED;
983         }
984
985         if (db_sam->transaction_start(db_sam) != 0) {
986                 DEBUG(0, ("Could not start transaction\n"));
987                 TALLOC_FREE(new_acct);
988                 return NT_STATUS_ACCESS_DENIED;
989
990         }
991
992         /* add the new account and lock it */
993         if ( !tdb_update_samacct_only(new_acct, TDB_INSERT) ) {
994                 goto cancel;
995         }
996
997         /* Rename the posix user.  Follow the semantics of _samr_create_user()
998            so that we lower case the posix name but preserve the case in passdb */
999
1000         fstrcpy( oldname_lower, pdb_get_username(old_acct) );
1001         strlower_m( oldname_lower );
1002
1003         fstrcpy( newname_lower, newname );
1004         strlower_m( newname_lower );
1005
1006         rename_script = talloc_string_sub2(new_acct,
1007                                 rename_script,
1008                                 "%unew",
1009                                 newname_lower,
1010                                 true,
1011                                 false,
1012                                 true);
1013         if (!rename_script) {
1014                 goto cancel;
1015         }
1016         rename_script = talloc_string_sub2(new_acct,
1017                                 rename_script,
1018                                 "%uold",
1019                                 oldname_lower,
1020                                 true,
1021                                 false,
1022                                 true);
1023         if (!rename_script) {
1024                 goto cancel;
1025         }
1026         rename_ret = smbrun(rename_script, NULL);
1027
1028         DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n",
1029                                 rename_script, rename_ret));
1030
1031         if (rename_ret != 0) {
1032                 goto cancel;
1033         }
1034
1035         smb_nscd_flush_user_cache();
1036
1037         /* rewrite the rid->username record */
1038
1039         if ( !tdb_update_ridrec_only( new_acct, TDB_MODIFY) ) {
1040                 goto cancel;
1041         }
1042
1043         tdb_delete_samacct_only( old_acct );
1044
1045         if (db_sam->transaction_commit(db_sam) != 0) {
1046                 /*
1047                  * Ok, we're screwed. We've changed the posix account, but
1048                  * could not adapt passdb.tdb. Shall we change the posix
1049                  * account back?
1050                  */
1051                 DEBUG(0, ("transaction_commit failed\n"));
1052                 TALLOC_FREE(new_acct);
1053                 return NT_STATUS_INTERNAL_DB_CORRUPTION;        
1054         }
1055
1056         TALLOC_FREE(new_acct );
1057         return NT_STATUS_OK;
1058
1059  cancel:
1060         if (db_sam->transaction_cancel(db_sam) != 0) {
1061                 smb_panic("transaction_cancel failed");
1062         }
1063
1064         TALLOC_FREE(new_acct);
1065
1066         return NT_STATUS_ACCESS_DENIED; 
1067 }
1068
1069 static bool tdbsam_rid_algorithm(struct pdb_methods *methods)
1070 {
1071         return False;
1072 }
1073
1074 static bool tdbsam_new_rid(struct pdb_methods *methods, uint32 *prid)
1075 {
1076         uint32 rid;
1077
1078         rid = BASE_RID;         /* Default if not set */
1079
1080         if (!tdbsam_open(tdbsam_filename)) {
1081                 DEBUG(0,("tdbsam_new_rid: failed to open %s!\n",
1082                         tdbsam_filename));
1083                 return false;
1084         }
1085
1086         if (dbwrap_change_uint32_atomic(db_sam, NEXT_RID_STRING, &rid, 1) != 0) {
1087                 DEBUG(3, ("tdbsam_new_rid: Failed to increase %s\n",
1088                         NEXT_RID_STRING));
1089                 return false;
1090         }
1091
1092         *prid = rid;
1093
1094         return true;
1095 }
1096
1097 struct tdbsam_search_state {
1098         struct pdb_methods *methods;
1099         uint32_t acct_flags;
1100
1101         uint32_t *rids;
1102         uint32_t num_rids;
1103         ssize_t array_size;
1104         uint32_t current;
1105 };
1106
1107 static int tdbsam_collect_rids(struct db_record *rec, void *private_data)
1108 {
1109         struct tdbsam_search_state *state = talloc_get_type_abort(
1110                 private_data, struct tdbsam_search_state);
1111         size_t prefixlen = strlen(RIDPREFIX);
1112         uint32 rid;
1113
1114         if ((rec->key.dsize < prefixlen)
1115             || (strncmp((char *)rec->key.dptr, RIDPREFIX, prefixlen))) {
1116                 return 0;
1117         }
1118
1119         rid = strtoul((char *)rec->key.dptr+prefixlen, NULL, 16);
1120
1121         ADD_TO_LARGE_ARRAY(state, uint32, rid, &state->rids, &state->num_rids,
1122                            &state->array_size);
1123
1124         return 0;
1125 }
1126
1127 static void tdbsam_search_end(struct pdb_search *search)
1128 {
1129         struct tdbsam_search_state *state = talloc_get_type_abort(
1130                 search->private_data, struct tdbsam_search_state);
1131         TALLOC_FREE(state);
1132 }
1133
1134 static bool tdbsam_search_next_entry(struct pdb_search *search,
1135                                      struct samr_displayentry *entry)
1136 {
1137         struct tdbsam_search_state *state = talloc_get_type_abort(
1138                 search->private_data, struct tdbsam_search_state);
1139         struct samu *user = NULL;
1140         NTSTATUS status;
1141         uint32_t rid;
1142
1143  again:
1144         TALLOC_FREE(user);
1145         user = samu_new(talloc_tos());
1146         if (user == NULL) {
1147                 DEBUG(0, ("samu_new failed\n"));
1148                 return false;
1149         }
1150
1151         if (state->current == state->num_rids) {
1152                 return false;
1153         }
1154
1155         rid = state->rids[state->current++];
1156
1157         status = tdbsam_getsampwrid(state->methods, user, rid);
1158
1159         if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
1160                 /*
1161                  * Someone has deleted that user since we listed the RIDs
1162                  */
1163                 goto again;
1164         }
1165
1166         if (!NT_STATUS_IS_OK(status)) {
1167                 DEBUG(10, ("tdbsam_getsampwrid failed: %s\n",
1168                            nt_errstr(status)));
1169                 TALLOC_FREE(user);
1170                 return false;
1171         }
1172
1173         if ((state->acct_flags != 0) &&
1174             ((state->acct_flags & pdb_get_acct_ctrl(user)) == 0)) {
1175                 goto again;
1176         }
1177
1178         entry->acct_flags = pdb_get_acct_ctrl(user);
1179         entry->rid = rid;
1180         entry->account_name = talloc_strdup(search, pdb_get_username(user));
1181         entry->fullname = talloc_strdup(search, pdb_get_fullname(user));
1182         entry->description = talloc_strdup(search, pdb_get_acct_desc(user));
1183
1184         TALLOC_FREE(user);
1185
1186         if ((entry->account_name == NULL) || (entry->fullname == NULL)
1187             || (entry->description == NULL)) {
1188                 DEBUG(0, ("talloc_strdup failed\n"));
1189                 return false;
1190         }
1191
1192         return true;
1193 }
1194
1195 static bool tdbsam_search_users(struct pdb_methods *methods,
1196                                 struct pdb_search *search,
1197                                 uint32 acct_flags)
1198 {
1199         struct tdbsam_search_state *state;
1200
1201         if (!tdbsam_open(tdbsam_filename)) {
1202                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n",
1203                          tdbsam_filename));
1204                 return false;
1205         }
1206
1207         state = talloc_zero(search, struct tdbsam_search_state);
1208         if (state == NULL) {
1209                 DEBUG(0, ("talloc failed\n"));
1210                 return false;
1211         }
1212         state->acct_flags = acct_flags;
1213         state->methods = methods;
1214
1215         db_sam->traverse_read(db_sam, tdbsam_collect_rids, state);
1216
1217         search->private_data = state;
1218         search->next_entry = tdbsam_search_next_entry;
1219         search->search_end = tdbsam_search_end;
1220
1221         return true;
1222 }
1223
1224 /*********************************************************************
1225  Initialize the tdb sam backend.  Setup the dispath table of methods,
1226  open the tdb, etc...
1227 *********************************************************************/
1228
1229 static NTSTATUS pdb_init_tdbsam(struct pdb_methods **pdb_method, const char *location)
1230 {
1231         NTSTATUS nt_status;
1232         char *tdbfile = NULL;
1233         const char *pfile = location;
1234
1235         if (!NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method ))) {
1236                 return nt_status;
1237         }
1238
1239         (*pdb_method)->name = "tdbsam";
1240
1241         (*pdb_method)->getsampwnam = tdbsam_getsampwnam;
1242         (*pdb_method)->getsampwsid = tdbsam_getsampwsid;
1243         (*pdb_method)->add_sam_account = tdbsam_add_sam_account;
1244         (*pdb_method)->update_sam_account = tdbsam_update_sam_account;
1245         (*pdb_method)->delete_sam_account = tdbsam_delete_sam_account;
1246         (*pdb_method)->rename_sam_account = tdbsam_rename_sam_account;
1247         (*pdb_method)->search_users = tdbsam_search_users;
1248
1249         (*pdb_method)->rid_algorithm = tdbsam_rid_algorithm;
1250         (*pdb_method)->new_rid = tdbsam_new_rid;
1251
1252         /* save the path for later */
1253
1254         if (!location) {
1255                 if (asprintf(&tdbfile, "%s/%s", lp_private_dir(),
1256                              PASSDB_FILE_NAME) < 0) {
1257                         return NT_STATUS_NO_MEMORY;
1258                 }
1259                 pfile = tdbfile;
1260         }
1261         tdbsam_filename = SMB_STRDUP(pfile);
1262         if (!tdbsam_filename) {
1263                 return NT_STATUS_NO_MEMORY;
1264         }
1265         SAFE_FREE(tdbfile);
1266
1267         /* no private data */
1268
1269         (*pdb_method)->private_data      = NULL;
1270         (*pdb_method)->free_private_data = NULL;
1271
1272         return NT_STATUS_OK;
1273 }
1274
1275 NTSTATUS pdb_tdbsam_init(void)
1276 {
1277         return smb_register_passdb(PASSDB_INTERFACE_VERSION, "tdbsam", pdb_init_tdbsam);
1278 }