s3:rpc_server/spoolss: remove reload_services check from delete_printer_hook()
[kai/samba.git] / source3 / passdb / pdb_tdb.c
1 /*
2  * Unix SMB/CIFS implementation. 
3  * SMB parameters and setup
4  * Copyright (C) Andrew Tridgell   1992-1998
5  * Copyright (C) Simo Sorce        2000-2003
6  * Copyright (C) Gerald Carter     2000-2006
7  * Copyright (C) Jeremy Allison    2001-2009
8  * Copyright (C) Andrew Bartlett   2002
9  * Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2005
10  * 
11  * This program is free software; you can redistribute it and/or modify it under
12  * the terms of the GNU General Public License as published by the Free
13  * Software Foundation; either version 3 of the License, or (at your option)
14  * any later version.
15  * 
16  * This program is distributed in the hope that it will be useful, but WITHOUT
17  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
19  * more details.
20  * 
21  * You should have received a copy of the GNU General Public License along with
22  * this program; if not, see <http://www.gnu.org/licenses/>.
23  */
24
25 #include "includes.h"
26 #include "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         status = dbwrap_store_uint32(db, NEXT_RID_STRING, rid);
349         if (!NT_STATUS_IS_OK(status)) {
350                 return false;
351         }
352
353         return true;
354 }
355
356 static bool tdbsam_convert(struct db_context **pp_db, const char *name, int32 from)
357 {
358         struct tdbsam_convert_state state;
359         struct db_context *db = NULL;
360         NTSTATUS status;
361
362         /* We only need the update backup for local db's. */
363         if (db_is_local(name) && !tdbsam_convert_backup(name, pp_db)) {
364                 DEBUG(0, ("tdbsam_convert: Could not backup %s\n", name));
365                 return false;
366         }
367
368         db = *pp_db;
369         state.from = from;
370         state.success = true;
371
372         if (dbwrap_transaction_start(db) != 0) {
373                 DEBUG(0, ("tdbsam_convert: Could not start transaction\n"));
374                 return false;
375         }
376
377         if (!tdbsam_upgrade_next_rid(db)) {
378                 DEBUG(0, ("tdbsam_convert: tdbsam_upgrade_next_rid failed\n"));
379                 goto cancel;
380         }
381
382         status = dbwrap_traverse(db, tdbsam_convert_one, &state, NULL);
383         if (!NT_STATUS_IS_OK(status)) {
384                 DEBUG(0, ("tdbsam_convert: traverse failed\n"));
385                 goto cancel;
386         }
387
388         if (!state.success) {
389                 DEBUG(0, ("tdbsam_convert: Converting records failed\n"));
390                 goto cancel;
391         }
392
393         status = dbwrap_store_int32(db, TDBSAM_VERSION_STRING,
394                                     TDBSAM_VERSION);
395         if (!NT_STATUS_IS_OK(status)) {
396                 DEBUG(0, ("tdbsam_convert: Could not store tdbsam version: "
397                           "%s\n", nt_errstr(status)));
398                 goto cancel;
399         }
400
401         status = dbwrap_store_int32(db, TDBSAM_MINOR_VERSION_STRING,
402                                     TDBSAM_MINOR_VERSION);
403         if (!NT_STATUS_IS_OK(status)) {
404                 DEBUG(0, ("tdbsam_convert: Could not store tdbsam minor "
405                           "version: %s\n", nt_errstr(status)));
406                 goto cancel;
407         }
408
409         if (dbwrap_transaction_commit(db) != 0) {
410                 DEBUG(0, ("tdbsam_convert: Could not commit transaction\n"));
411                 return false;
412         }
413
414         return true;
415
416  cancel:
417         if (dbwrap_transaction_cancel(db) != 0) {
418                 smb_panic("tdbsam_convert: transaction_cancel failed");
419         }
420
421         return false;
422 }
423
424 /*********************************************************************
425  Open the tdbsam file based on the absolute path specified.
426  Uses a reference count to allow multiple open calls.
427 *********************************************************************/
428
429 static bool tdbsam_open( const char *name )
430 {
431         int32   version;
432         int32   minor_version;
433         NTSTATUS status;
434
435         /* check if we are already open */
436
437         if ( db_sam ) {
438                 return true;
439         }
440
441         /* Try to open tdb passwd.  Create a new one if necessary */
442
443         db_sam = db_open(NULL, name, 0, TDB_DEFAULT, O_CREAT|O_RDWR, 0600);
444         if (db_sam == NULL) {
445                 DEBUG(0, ("tdbsam_open: Failed to open/create TDB passwd "
446                           "[%s]\n", name));
447                 return false;
448         }
449
450         /* Check the version */
451         status = dbwrap_fetch_int32(db_sam, TDBSAM_VERSION_STRING, &version);
452         if (!NT_STATUS_IS_OK(status)) {
453                 version = 0;    /* Version not found, assume version 0 */
454         }
455
456         /* Get the minor version */
457         status = dbwrap_fetch_int32(db_sam, TDBSAM_MINOR_VERSION_STRING,
458                                     &minor_version);
459         if (!NT_STATUS_IS_OK(status)) {
460                 minor_version = 0; /* Minor version not found, assume 0 */
461         }
462
463         /* Compare the version */
464         if (version > TDBSAM_VERSION) {
465                 /* Version more recent than the latest known */
466                 DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
467                 TALLOC_FREE(db_sam);
468                 return false;
469         }
470
471         if ( version < TDBSAM_VERSION ||
472                         (version == TDBSAM_VERSION &&
473                          minor_version < TDBSAM_MINOR_VERSION) ) {
474                 /*
475                  * Ok - we think we're going to have to convert.
476                  * Due to the backup process we now must do to
477                  * upgrade we have to get a mutex and re-check
478                  * the version. Someone else may have upgraded
479                  * whilst we were checking.
480                  */
481
482                 struct named_mutex *mtx = grab_named_mutex(NULL,
483                                                 "tdbsam_upgrade_mutex",
484                                                 600);
485
486                 if (!mtx) {
487                         DEBUG(0, ("tdbsam_open: failed to grab mutex.\n"));
488                         TALLOC_FREE(db_sam);
489                         return false;
490                 }
491
492                 /* Re-check the version */
493                 status = dbwrap_fetch_int32(db_sam, TDBSAM_VERSION_STRING,
494                                             &version);
495                 if (!NT_STATUS_IS_OK(status)) {
496                         version = 0;    /* Version not found, assume version 0 */
497                 }
498
499                 /* Re-check the minor version */
500                 status = dbwrap_fetch_int32(db_sam, TDBSAM_MINOR_VERSION_STRING,
501                                             &minor_version);
502                 if (!NT_STATUS_IS_OK(status)) {
503                         minor_version = 0; /* Minor version not found, assume 0 */
504                 }
505
506                 /* Compare the version */
507                 if (version > TDBSAM_VERSION) {
508                         /* Version more recent than the latest known */
509                         DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
510                         TALLOC_FREE(db_sam);
511                         TALLOC_FREE(mtx);
512                         return false;
513                 }
514
515                 if ( version < TDBSAM_VERSION ||
516                                 (version == TDBSAM_VERSION &&
517                                  minor_version < TDBSAM_MINOR_VERSION) ) {
518                         /*
519                          * Note that minor versions we read that are greater
520                          * than the current minor version we have hard coded
521                          * are assumed to be compatible if they have the same
522                          * major version. That allows previous versions of the
523                          * passdb code that don't know about minor versions to
524                          * still use this database. JRA.
525                          */
526
527                         DEBUG(1, ("tdbsam_open: Converting version %d.%d database to "
528                                   "version %d.%d.\n",
529                                         version,
530                                         minor_version,
531                                         TDBSAM_VERSION,
532                                         TDBSAM_MINOR_VERSION));
533
534                         if ( !tdbsam_convert(&db_sam, name, version) ) {
535                                 DEBUG(0, ("tdbsam_open: Error when trying to convert "
536                                           "tdbsam [%s]\n",name));
537                                 TALLOC_FREE(db_sam);
538                                 TALLOC_FREE(mtx);
539                                 return false;
540                         }
541
542                         DEBUG(3, ("TDBSAM converted successfully.\n"));
543                 }
544                 TALLOC_FREE(mtx);
545         }
546
547         DEBUG(4,("tdbsam_open: successfully opened %s\n", name ));
548
549         return true;
550 }
551
552 /******************************************************************
553  Lookup a name in the SAM TDB
554 ******************************************************************/
555
556 static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods,
557                                     struct samu *user, const char *sname)
558 {
559         TDB_DATA        data;
560         fstring         keystr;
561         fstring         name;
562         NTSTATUS status;
563
564         if ( !user ) {
565                 DEBUG(0,("pdb_getsampwnam: struct samu is NULL.\n"));
566                 return NT_STATUS_NO_MEMORY;
567         }
568
569         /* Data is stored in all lower-case */
570         fstrcpy(name, sname);
571         strlower_m(name);
572
573         /* set search key */
574         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
575
576         /* open the database */
577
578         if ( !tdbsam_open( tdbsam_filename ) ) {
579                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
580                 return NT_STATUS_ACCESS_DENIED;
581         }
582
583         /* get the record */
584
585         status = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr, &data);
586         if (!NT_STATUS_IS_OK(status)) {
587                 DEBUG(5,("pdb_getsampwnam (TDB): error fetching database.\n"));
588                 DEBUGADD(5, (" Key: %s\n", keystr));
589                 return NT_STATUS_NO_SUCH_USER;
590         }
591
592         /* unpack the buffer */
593
594         if (!init_samu_from_buffer(user, SAMU_BUFFER_LATEST, data.dptr, data.dsize)) {
595                 DEBUG(0,("pdb_getsampwent: Bad struct samu entry returned from TDB!\n"));
596                 SAFE_FREE(data.dptr);
597                 return NT_STATUS_NO_MEMORY;
598         }
599
600         /* success */
601
602         TALLOC_FREE(data.dptr);
603
604         return NT_STATUS_OK;
605 }
606
607 /***************************************************************************
608  Search by rid
609  **************************************************************************/
610
611 static NTSTATUS tdbsam_getsampwrid (struct pdb_methods *my_methods,
612                                     struct samu *user, uint32 rid)
613 {
614         NTSTATUS                nt_status = NT_STATUS_UNSUCCESSFUL;
615         TDB_DATA                data;
616         fstring                 keystr;
617         fstring                 name;
618
619         if ( !user ) {
620                 DEBUG(0,("pdb_getsampwrid: struct samu is NULL.\n"));
621                 return nt_status;
622         }
623
624         /* set search key */
625
626         slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
627
628         /* open the database */
629
630         if ( !tdbsam_open( tdbsam_filename ) ) {
631                 DEBUG(0,("tdbsam_getsampwrid: failed to open %s!\n", tdbsam_filename));
632                 return NT_STATUS_ACCESS_DENIED;
633         }
634
635         /* get the record */
636
637         nt_status = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr, &data);
638         if (!NT_STATUS_IS_OK(nt_status)) {
639                 DEBUG(5,("pdb_getsampwrid (TDB): error looking up RID %d by key %s.\n", rid, keystr));
640                 return nt_status;
641         }
642
643         fstrcpy(name, (const char *)data.dptr);
644         TALLOC_FREE(data.dptr);
645
646         return tdbsam_getsampwnam (my_methods, user, name);
647 }
648
649 static NTSTATUS tdbsam_getsampwsid(struct pdb_methods *my_methods,
650                                    struct samu * user, const struct dom_sid *sid)
651 {
652         uint32 rid;
653
654         if ( !sid_peek_check_rid(get_global_sam_sid(), sid, &rid) )
655                 return NT_STATUS_UNSUCCESSFUL;
656
657         return tdbsam_getsampwrid(my_methods, user, rid);
658 }
659
660 static bool tdb_delete_samacct_only( struct samu *sam_pass )
661 {
662         fstring         keystr;
663         fstring         name;
664         NTSTATUS status;
665
666         fstrcpy(name, pdb_get_username(sam_pass));
667         strlower_m(name);
668
669         /* set the search key */
670
671         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
672
673         /* it's outaa here!  8^) */
674         if ( !tdbsam_open( tdbsam_filename ) ) {
675                 DEBUG(0,("tdb_delete_samacct_only: failed to open %s!\n",
676                          tdbsam_filename));
677                 return false;
678         }
679
680         status = dbwrap_delete_bystring(db_sam, keystr);
681         if (!NT_STATUS_IS_OK(status)) {
682                 DEBUG(5, ("Error deleting entry from tdb passwd "
683                           "database: %s!\n", nt_errstr(status)));
684                 return false;
685         }
686
687         return true;
688 }
689
690 /***************************************************************************
691  Delete a struct samu records for the username and RID key
692 ****************************************************************************/
693
694 static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods,
695                                           struct samu *sam_pass)
696 {
697         NTSTATUS        nt_status = NT_STATUS_UNSUCCESSFUL;
698         fstring         keystr;
699         uint32          rid;
700         fstring         name;
701
702         /* open the database */
703
704         if ( !tdbsam_open( tdbsam_filename ) ) {
705                 DEBUG(0,("tdbsam_delete_sam_account: failed to open %s!\n",
706                          tdbsam_filename));
707                 return NT_STATUS_ACCESS_DENIED;
708         }
709
710         fstrcpy(name, pdb_get_username(sam_pass));
711         strlower_m(name);
712
713         /* set the search key */
714
715         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
716
717         rid = pdb_get_user_rid(sam_pass);
718
719         /* it's outaa here!  8^) */
720
721         if (dbwrap_transaction_start(db_sam) != 0) {
722                 DEBUG(0, ("Could not start transaction\n"));
723                 return NT_STATUS_UNSUCCESSFUL;
724         }
725
726         nt_status = dbwrap_delete_bystring(db_sam, keystr);
727         if (!NT_STATUS_IS_OK(nt_status)) {
728                 DEBUG(5, ("Error deleting entry from tdb passwd "
729                           "database: %s!\n", nt_errstr(nt_status)));
730                 goto cancel;
731         }
732
733         /* set the search key */
734
735         slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
736
737         /* it's outaa here!  8^) */
738
739         nt_status = dbwrap_delete_bystring(db_sam, keystr);
740         if (!NT_STATUS_IS_OK(nt_status)) {
741                 DEBUG(5, ("Error deleting entry from tdb rid "
742                           "database: %s!\n", nt_errstr(nt_status)));
743                 goto cancel;
744         }
745
746         if (dbwrap_transaction_commit(db_sam) != 0) {
747                 DEBUG(0, ("Could not commit transaction\n"));
748                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
749         }
750
751         return NT_STATUS_OK;
752
753  cancel:
754         if (dbwrap_transaction_cancel(db_sam) != 0) {
755                 smb_panic("transaction_cancel failed");
756         }
757
758         return nt_status;
759 }
760
761
762 /***************************************************************************
763  Update the TDB SAM account record only
764  Assumes that the tdbsam is already open 
765 ****************************************************************************/
766 static bool tdb_update_samacct_only( struct samu* newpwd, int flag )
767 {
768         TDB_DATA        data;
769         uint8           *buf = NULL;
770         fstring         keystr;
771         fstring         name;
772         bool            ret = false;
773         NTSTATUS status;
774
775         /* copy the struct samu struct into a BYTE buffer for storage */
776
777         if ( (data.dsize=init_buffer_from_samu(&buf, newpwd, False)) == -1 ) {
778                 DEBUG(0,("tdb_update_sam: ERROR - Unable to copy struct samu info BYTE buffer!\n"));
779                 goto done;
780         }
781         data.dptr = buf;
782
783         fstrcpy(name, pdb_get_username(newpwd));
784         strlower_m(name);
785
786         DEBUG(5, ("Storing %saccount %s with RID %d\n",
787                   flag == TDB_INSERT ? "(new) " : "", name,
788                   pdb_get_user_rid(newpwd)));
789
790         /* setup the USER index key */
791         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
792
793         /* add the account */
794
795         status = dbwrap_store_bystring(db_sam, keystr, data, flag);
796         if (!NT_STATUS_IS_OK(status)) {
797                 DEBUG(0, ("Unable to modify passwd TDB: %s!",
798                           nt_errstr(status)));
799                 goto done;
800         }
801
802         ret = true;
803
804 done:
805         /* cleanup */
806         SAFE_FREE(buf);
807         return ret;
808 }
809
810 /***************************************************************************
811  Update the TDB SAM RID record only
812  Assumes that the tdbsam is already open
813 ****************************************************************************/
814 static bool tdb_update_ridrec_only( struct samu* newpwd, int flag )
815 {
816         TDB_DATA        data;
817         fstring         keystr;
818         fstring         name;
819         NTSTATUS status;
820
821         fstrcpy(name, pdb_get_username(newpwd));
822         strlower_m(name);
823
824         /* setup RID data */
825         data = string_term_tdb_data(name);
826
827         /* setup the RID index key */
828         slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX,
829                  pdb_get_user_rid(newpwd));
830
831         /* add the reference */
832         status = dbwrap_store_bystring(db_sam, keystr, data, flag);
833         if (!NT_STATUS_IS_OK(status)) {
834                 DEBUG(0, ("Unable to modify TDB passwd: %s!\n",
835                           nt_errstr(status)));
836                 return false;
837         }
838
839         return true;
840
841 }
842
843 /***************************************************************************
844  Update the TDB SAM
845 ****************************************************************************/
846
847 static bool tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd,
848                            int flag)
849 {
850         uint32_t oldrid;
851         uint32_t newrid;
852
853         if (!(newrid = pdb_get_user_rid(newpwd))) {
854                 DEBUG(0,("tdb_update_sam: struct samu (%s) with no RID!\n",
855                          pdb_get_username(newpwd)));
856                 return False;
857         }
858
859         oldrid = newrid;
860
861         /* open the database */
862
863         if ( !tdbsam_open( tdbsam_filename ) ) {
864                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
865                 return False;
866         }
867
868         if (dbwrap_transaction_start(db_sam) != 0) {
869                 DEBUG(0, ("Could not start transaction\n"));
870                 return false;
871         }
872
873         /* If we are updating, we may be changing this users RID. Retrieve the old RID
874            so we can check. */
875
876         if (flag == TDB_MODIFY) {
877                 struct samu *account = samu_new(talloc_tos());
878                 if (account == NULL) {
879                         DEBUG(0,("tdb_update_sam: samu_new() failed\n"));
880                         goto cancel;
881                 }
882                 if (!NT_STATUS_IS_OK(tdbsam_getsampwnam(my_methods, account, pdb_get_username(newpwd)))) {
883                         DEBUG(0,("tdb_update_sam: tdbsam_getsampwnam() for %s failed\n",
884                                 pdb_get_username(newpwd)));
885                         TALLOC_FREE(account);
886                         goto cancel;
887                 }
888                 if (!(oldrid = pdb_get_user_rid(account))) {
889                         DEBUG(0,("tdb_update_sam: pdb_get_user_rid() failed\n"));
890                         TALLOC_FREE(account);
891                         goto cancel;
892                 }
893                 TALLOC_FREE(account);
894         }
895
896         /* Update the new samu entry. */
897         if (!tdb_update_samacct_only(newpwd, flag)) {
898                 goto cancel;
899         }
900
901         /* Now take care of the case where the RID changed. We need
902          * to delete the old RID key and add the new. */
903
904         if (flag == TDB_MODIFY && newrid != oldrid) { 
905                 fstring keystr;
906
907                 /* Delete old RID key */
908                 DEBUG(10, ("tdb_update_sam: Deleting key for RID %u\n", oldrid));
909                 slprintf(keystr, sizeof(keystr) - 1, "%s%.8x", RIDPREFIX, oldrid);
910                 if (!NT_STATUS_IS_OK(dbwrap_delete_bystring(db_sam, keystr))) {
911                         DEBUG(0, ("tdb_update_sam: Can't delete %s\n", keystr));
912                         goto cancel;
913                 }
914                 /* Insert new RID key */
915                 DEBUG(10, ("tdb_update_sam: Inserting key for RID %u\n", newrid));
916                 if (!tdb_update_ridrec_only(newpwd, TDB_INSERT)) {
917                         goto cancel;
918                 }
919         } else {
920                 DEBUG(10, ("tdb_update_sam: %s key for RID %u\n",
921                         flag == TDB_MODIFY ? "Updating" : "Inserting", newrid));
922                 if (!tdb_update_ridrec_only(newpwd, flag)) {
923                         goto cancel;
924                 }
925         }
926
927         if (dbwrap_transaction_commit(db_sam) != 0) {
928                 DEBUG(0, ("Could not commit transaction\n"));
929                 return false;
930         }
931
932         return true;
933
934  cancel:
935         if (dbwrap_transaction_cancel(db_sam) != 0) {
936                 smb_panic("transaction_cancel failed");
937         }
938         return false;
939 }
940
941 /***************************************************************************
942  Modifies an existing struct samu
943 ****************************************************************************/
944
945 static NTSTATUS tdbsam_update_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
946 {
947         if ( !tdb_update_sam(my_methods, newpwd, TDB_MODIFY) )
948                 return NT_STATUS_UNSUCCESSFUL;
949         
950         return NT_STATUS_OK;
951 }
952
953 /***************************************************************************
954  Adds an existing struct samu
955 ****************************************************************************/
956
957 static NTSTATUS tdbsam_add_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
958 {
959         if ( !tdb_update_sam(my_methods, newpwd, TDB_INSERT) )
960                 return NT_STATUS_UNSUCCESSFUL;
961                 
962         return NT_STATUS_OK;
963 }
964
965 /***************************************************************************
966  Renames a struct samu
967  - check for the posix user/rename user script
968  - Add and lock the new user record
969  - rename the posix user
970  - rewrite the rid->username record
971  - delete the old user
972  - unlock the new user record
973 ***************************************************************************/
974 static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
975                                           struct samu *old_acct,
976                                           const char *newname)
977 {
978         struct samu      *new_acct = NULL;
979         char *rename_script = NULL;
980         int              rename_ret;
981         fstring          oldname_lower;
982         fstring          newname_lower;
983
984         /* can't do anything without an external script */
985
986         if ( !(new_acct = samu_new( talloc_tos() )) ) {
987                 return NT_STATUS_NO_MEMORY;
988         }
989
990         rename_script = talloc_strdup(new_acct, lp_renameuser_script());
991         if (!rename_script) {
992                 TALLOC_FREE(new_acct);
993                 return NT_STATUS_NO_MEMORY;
994         }
995         if (!*rename_script) {
996                 TALLOC_FREE(new_acct);
997                 return NT_STATUS_ACCESS_DENIED;
998         }
999
1000         if ( !pdb_copy_sam_account(new_acct, old_acct)
1001                 || !pdb_set_username(new_acct, newname, PDB_CHANGED))
1002         {
1003                 TALLOC_FREE(new_acct);
1004                 return NT_STATUS_NO_MEMORY;
1005         }
1006
1007         /* open the database */
1008         if ( !tdbsam_open( tdbsam_filename ) ) {
1009                 DEBUG(0, ("tdbsam_getsampwnam: failed to open %s!\n",
1010                           tdbsam_filename));
1011                 TALLOC_FREE(new_acct);
1012                 return NT_STATUS_ACCESS_DENIED;
1013         }
1014
1015         if (dbwrap_transaction_start(db_sam) != 0) {
1016                 DEBUG(0, ("Could not start transaction\n"));
1017                 TALLOC_FREE(new_acct);
1018                 return NT_STATUS_ACCESS_DENIED;
1019
1020         }
1021
1022         /* add the new account and lock it */
1023         if ( !tdb_update_samacct_only(new_acct, TDB_INSERT) ) {
1024                 goto cancel;
1025         }
1026
1027         /* Rename the posix user.  Follow the semantics of _samr_create_user()
1028            so that we lower case the posix name but preserve the case in passdb */
1029
1030         fstrcpy( oldname_lower, pdb_get_username(old_acct) );
1031         strlower_m( oldname_lower );
1032
1033         fstrcpy( newname_lower, newname );
1034         strlower_m( newname_lower );
1035
1036         rename_script = talloc_string_sub2(new_acct,
1037                                 rename_script,
1038                                 "%unew",
1039                                 newname_lower,
1040                                 true,
1041                                 false,
1042                                 true);
1043         if (!rename_script) {
1044                 goto cancel;
1045         }
1046         rename_script = talloc_string_sub2(new_acct,
1047                                 rename_script,
1048                                 "%uold",
1049                                 oldname_lower,
1050                                 true,
1051                                 false,
1052                                 true);
1053         if (!rename_script) {
1054                 goto cancel;
1055         }
1056         rename_ret = smbrun(rename_script, NULL);
1057
1058         DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n",
1059                                 rename_script, rename_ret));
1060
1061         if (rename_ret != 0) {
1062                 goto cancel;
1063         }
1064
1065         smb_nscd_flush_user_cache();
1066
1067         /* rewrite the rid->username record */
1068
1069         if ( !tdb_update_ridrec_only( new_acct, TDB_MODIFY) ) {
1070                 goto cancel;
1071         }
1072
1073         tdb_delete_samacct_only( old_acct );
1074
1075         if (dbwrap_transaction_commit(db_sam) != 0) {
1076                 /*
1077                  * Ok, we're screwed. We've changed the posix account, but
1078                  * could not adapt passdb.tdb. Shall we change the posix
1079                  * account back?
1080                  */
1081                 DEBUG(0, ("transaction_commit failed\n"));
1082                 TALLOC_FREE(new_acct);
1083                 return NT_STATUS_INTERNAL_DB_CORRUPTION;        
1084         }
1085
1086         TALLOC_FREE(new_acct );
1087         return NT_STATUS_OK;
1088
1089  cancel:
1090         if (dbwrap_transaction_cancel(db_sam) != 0) {
1091                 smb_panic("transaction_cancel failed");
1092         }
1093
1094         TALLOC_FREE(new_acct);
1095
1096         return NT_STATUS_ACCESS_DENIED; 
1097 }
1098
1099 static uint32_t tdbsam_capabilities(struct pdb_methods *methods)
1100 {
1101         return PDB_CAP_STORE_RIDS;
1102 }
1103
1104 static bool tdbsam_new_rid(struct pdb_methods *methods, uint32 *prid)
1105 {
1106         uint32 rid;
1107         NTSTATUS status;
1108
1109         rid = BASE_RID;         /* Default if not set */
1110
1111         if (!tdbsam_open(tdbsam_filename)) {
1112                 DEBUG(0,("tdbsam_new_rid: failed to open %s!\n",
1113                         tdbsam_filename));
1114                 return false;
1115         }
1116
1117         status = dbwrap_trans_change_uint32_atomic(db_sam, NEXT_RID_STRING,
1118                                                    &rid, 1);
1119         if (!NT_STATUS_IS_OK(status)) {
1120                 DEBUG(3, ("tdbsam_new_rid: Failed to increase %s: %s\n",
1121                         NEXT_RID_STRING, nt_errstr(status)));
1122                 return false;
1123         }
1124
1125         *prid = rid;
1126
1127         return true;
1128 }
1129
1130 struct tdbsam_search_state {
1131         struct pdb_methods *methods;
1132         uint32_t acct_flags;
1133
1134         uint32_t *rids;
1135         uint32_t num_rids;
1136         ssize_t array_size;
1137         uint32_t current;
1138 };
1139
1140 static int tdbsam_collect_rids(struct db_record *rec, void *private_data)
1141 {
1142         struct tdbsam_search_state *state = talloc_get_type_abort(
1143                 private_data, struct tdbsam_search_state);
1144         size_t prefixlen = strlen(RIDPREFIX);
1145         uint32 rid;
1146         TDB_DATA key;
1147
1148         key = dbwrap_record_get_key(rec);
1149
1150         if ((key.dsize < prefixlen)
1151             || (strncmp((char *)key.dptr, RIDPREFIX, prefixlen))) {
1152                 return 0;
1153         }
1154
1155         rid = strtoul((char *)key.dptr+prefixlen, NULL, 16);
1156
1157         ADD_TO_LARGE_ARRAY(state, uint32, rid, &state->rids, &state->num_rids,
1158                            &state->array_size);
1159
1160         return 0;
1161 }
1162
1163 static void tdbsam_search_end(struct pdb_search *search)
1164 {
1165         struct tdbsam_search_state *state = talloc_get_type_abort(
1166                 search->private_data, struct tdbsam_search_state);
1167         TALLOC_FREE(state);
1168 }
1169
1170 static bool tdbsam_search_next_entry(struct pdb_search *search,
1171                                      struct samr_displayentry *entry)
1172 {
1173         struct tdbsam_search_state *state = talloc_get_type_abort(
1174                 search->private_data, struct tdbsam_search_state);
1175         struct samu *user = NULL;
1176         NTSTATUS status;
1177         uint32_t rid;
1178
1179  again:
1180         TALLOC_FREE(user);
1181         user = samu_new(talloc_tos());
1182         if (user == NULL) {
1183                 DEBUG(0, ("samu_new failed\n"));
1184                 return false;
1185         }
1186
1187         if (state->current == state->num_rids) {
1188                 return false;
1189         }
1190
1191         rid = state->rids[state->current++];
1192
1193         status = tdbsam_getsampwrid(state->methods, user, rid);
1194
1195         if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
1196                 /*
1197                  * Someone has deleted that user since we listed the RIDs
1198                  */
1199                 goto again;
1200         }
1201
1202         if (!NT_STATUS_IS_OK(status)) {
1203                 DEBUG(10, ("tdbsam_getsampwrid failed: %s\n",
1204                            nt_errstr(status)));
1205                 TALLOC_FREE(user);
1206                 return false;
1207         }
1208
1209         if ((state->acct_flags != 0) &&
1210             ((state->acct_flags & pdb_get_acct_ctrl(user)) == 0)) {
1211                 goto again;
1212         }
1213
1214         entry->acct_flags = pdb_get_acct_ctrl(user);
1215         entry->rid = rid;
1216         entry->account_name = talloc_strdup(search, pdb_get_username(user));
1217         entry->fullname = talloc_strdup(search, pdb_get_fullname(user));
1218         entry->description = talloc_strdup(search, pdb_get_acct_desc(user));
1219
1220         TALLOC_FREE(user);
1221
1222         if ((entry->account_name == NULL) || (entry->fullname == NULL)
1223             || (entry->description == NULL)) {
1224                 DEBUG(0, ("talloc_strdup failed\n"));
1225                 return false;
1226         }
1227
1228         return true;
1229 }
1230
1231 static bool tdbsam_search_users(struct pdb_methods *methods,
1232                                 struct pdb_search *search,
1233                                 uint32 acct_flags)
1234 {
1235         struct tdbsam_search_state *state;
1236
1237         if (!tdbsam_open(tdbsam_filename)) {
1238                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n",
1239                          tdbsam_filename));
1240                 return false;
1241         }
1242
1243         state = talloc_zero(search, struct tdbsam_search_state);
1244         if (state == NULL) {
1245                 DEBUG(0, ("talloc failed\n"));
1246                 return false;
1247         }
1248         state->acct_flags = acct_flags;
1249         state->methods = methods;
1250
1251         dbwrap_traverse_read(db_sam, tdbsam_collect_rids, state, NULL);
1252
1253         search->private_data = state;
1254         search->next_entry = tdbsam_search_next_entry;
1255         search->search_end = tdbsam_search_end;
1256
1257         return true;
1258 }
1259
1260 /*********************************************************************
1261  Initialize the tdb sam backend.  Setup the dispath table of methods,
1262  open the tdb, etc...
1263 *********************************************************************/
1264
1265 static NTSTATUS pdb_init_tdbsam(struct pdb_methods **pdb_method, const char *location)
1266 {
1267         NTSTATUS nt_status;
1268         char *tdbfile = NULL;
1269         const char *pfile = location;
1270
1271         if (!NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method ))) {
1272                 return nt_status;
1273         }
1274
1275         (*pdb_method)->name = "tdbsam";
1276
1277         (*pdb_method)->getsampwnam = tdbsam_getsampwnam;
1278         (*pdb_method)->getsampwsid = tdbsam_getsampwsid;
1279         (*pdb_method)->add_sam_account = tdbsam_add_sam_account;
1280         (*pdb_method)->update_sam_account = tdbsam_update_sam_account;
1281         (*pdb_method)->delete_sam_account = tdbsam_delete_sam_account;
1282         (*pdb_method)->rename_sam_account = tdbsam_rename_sam_account;
1283         (*pdb_method)->search_users = tdbsam_search_users;
1284
1285         (*pdb_method)->capabilities = tdbsam_capabilities;
1286         (*pdb_method)->new_rid = tdbsam_new_rid;
1287
1288         /* save the path for later */
1289
1290         if (!location) {
1291                 if (asprintf(&tdbfile, "%s/%s", lp_private_dir(),
1292                              PASSDB_FILE_NAME) < 0) {
1293                         return NT_STATUS_NO_MEMORY;
1294                 }
1295                 pfile = tdbfile;
1296         }
1297         tdbsam_filename = SMB_STRDUP(pfile);
1298         if (!tdbsam_filename) {
1299                 return NT_STATUS_NO_MEMORY;
1300         }
1301         SAFE_FREE(tdbfile);
1302
1303         /* no private data */
1304
1305         (*pdb_method)->private_data      = NULL;
1306         (*pdb_method)->free_private_data = NULL;
1307
1308         return NT_STATUS_OK;
1309 }
1310
1311 NTSTATUS pdb_tdbsam_init(void)
1312 {
1313         return smb_register_passdb(PASSDB_INTERFACE_VERSION, "tdbsam", pdb_init_tdbsam);
1314 }