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