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