s4: make libintl a build dependency of heimdal_krb5 so all dependent binaries are...
[tprouty/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
8  * Copyright (C) Andrew Bartlett   2002
9  * Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2005
10  * 
11  * This program is free software; you can redistribute it and/or modify it under
12  * the terms of the GNU General Public License as published by the Free
13  * Software Foundation; either version 3 of the License, or (at your option)
14  * any later version.
15  * 
16  * This program is distributed in the hope that it will be useful, but WITHOUT
17  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
19  * more details.
20  * 
21  * You should have received a copy of the GNU General Public License along with
22  * this program; if not, see <http://www.gnu.org/licenses/>.
23  */
24
25 #include "includes.h"
26
27 #if 0 /* when made a module use this */
28
29 static int tdbsam_debug_level = DBGC_ALL;
30 #undef DBGC_CLASS
31 #define DBGC_CLASS tdbsam_debug_level
32
33 #else
34
35 #undef DBGC_CLASS
36 #define DBGC_CLASS DBGC_PASSDB
37
38 #endif
39
40 #define TDBSAM_VERSION  4       /* Most recent TDBSAM version */
41 #define TDBSAM_VERSION_STRING   "INFO/version"
42 #define PASSDB_FILE_NAME        "passdb.tdb"
43 #define USERPREFIX              "USER_"
44 #define USERPREFIX_LEN          5
45 #define RIDPREFIX               "RID_"
46 #define PRIVPREFIX              "PRIV_"
47 #define NEXT_RID_STRING         "NEXT_RID"
48
49 /* GLOBAL TDB SAM CONTEXT */
50
51 static struct db_context *db_sam;
52 static char *tdbsam_filename;
53
54 struct tdbsam_convert_state {
55         int32_t from;
56         bool success;
57 };
58
59 static int tdbsam_convert_one(struct db_record *rec, void *priv)
60 {
61         struct tdbsam_convert_state *state =
62                 (struct tdbsam_convert_state *)priv;
63         struct samu *user;
64         TDB_DATA data;
65         NTSTATUS status;
66         bool ret;
67
68         if (rec->key.dsize < USERPREFIX_LEN) {
69                 return 0;
70         }
71         if (strncmp((char *)rec->key.dptr, USERPREFIX, USERPREFIX_LEN) != 0) {
72                 return 0;
73         }
74
75         user = samu_new(talloc_tos());
76         if (user == NULL) {
77                 DEBUG(0,("tdbsam_convert: samu_new() failed!\n"));
78                 state->success = false;
79                 return -1;
80         }
81
82         DEBUG(10,("tdbsam_convert: Try unpacking a record with (key:%s) "
83                   "(version:%d)\n", rec->key.dptr, state->from));
84
85         switch (state->from) {
86         case 0:
87                 ret = init_samu_from_buffer(user, SAMU_BUFFER_V0,
88                                             (uint8 *)rec->value.dptr,
89                                             rec->value.dsize);
90                 break;
91         case 1:
92                 ret = init_samu_from_buffer(user, SAMU_BUFFER_V1,
93                                             (uint8 *)rec->value.dptr,
94                                             rec->value.dsize);
95                 break;
96         case 2:
97                 ret = init_samu_from_buffer(user, SAMU_BUFFER_V2,
98                                             (uint8 *)rec->value.dptr,
99                                             rec->value.dsize);
100                 break;
101         case 3:
102                 ret = init_samu_from_buffer(user, SAMU_BUFFER_V3,
103                                             (uint8 *)rec->value.dptr,
104                                             rec->value.dsize);
105         case 4:
106                 ret = init_samu_from_buffer(user, SAMU_BUFFER_V4,
107                                             (uint8 *)rec->value.dptr,
108                                             rec->value.dsize);
109                 break;
110         default:
111                 /* unknown tdbsam version */
112                 ret = False;
113         }
114         if (!ret) {
115                 DEBUG(0,("tdbsam_convert: Bad struct samu entry returned "
116                          "from TDB (key:%s) (version:%d)\n", rec->key.dptr,
117                          state->from));
118                 TALLOC_FREE(user);
119                 state->success = false;
120                 return -1;
121         }
122
123         data.dsize = init_buffer_from_samu(&data.dptr, user, false);
124         TALLOC_FREE(user);
125
126         if (data.dsize == -1) {
127                 DEBUG(0,("tdbsam_convert: cannot pack the struct samu into "
128                          "the new format\n"));
129                 state->success = false;
130                 return -1;
131         }
132
133         status = rec->store(rec, data, TDB_MODIFY);
134         if (!NT_STATUS_IS_OK(status)) {
135                 DEBUG(0, ("Could not store the new record: %s\n",
136                           nt_errstr(status)));
137                 state->success = false;
138                 return -1;
139         }
140
141         return 0;
142 }
143
144 static bool tdbsam_upgrade_next_rid(struct db_context *db)
145 {
146         TDB_CONTEXT *tdb;
147         uint32 rid;
148         bool ok = false;
149
150         ok = dbwrap_fetch_uint32(db, NEXT_RID_STRING, &rid);
151         if (ok) {
152                 return true;
153         }
154
155         tdb = tdb_open_log(state_path("winbindd_idmap.tdb"), 0,
156                            TDB_DEFAULT, O_RDONLY, 0644);
157
158         if (tdb) {
159                 ok = tdb_fetch_uint32(tdb, "RID_COUNTER", &rid);
160                 if (!ok) {
161                         rid = BASE_RID;
162                 }
163                 tdb_close(tdb);
164         } else {
165                 rid = BASE_RID;
166         }
167
168         if (dbwrap_store_uint32(db, NEXT_RID_STRING, rid) != 0) {
169                 return false;
170         }
171
172         return true;
173 }
174
175 static bool tdbsam_convert(struct db_context *db, int32 from)
176 {
177         struct tdbsam_convert_state state;
178         int ret;
179
180         state.from = from;
181         state.success = true;
182
183         if (db->transaction_start(db) != 0) {
184                 DEBUG(0, ("Could not start transaction\n"));
185                 return false;
186         }
187
188         if (!tdbsam_upgrade_next_rid(db)) {
189                 DEBUG(0, ("tdbsam_upgrade_next_rid failed\n"));
190                 goto cancel;
191         }
192
193         ret = db->traverse(db, tdbsam_convert_one, &state);
194         if (ret < 0) {
195                 DEBUG(0, ("traverse failed\n"));
196                 goto cancel;
197         }
198
199         if (!state.success) {
200                 DEBUG(0, ("Converting records failed\n"));
201                 goto cancel;
202         }
203
204         if (dbwrap_store_int32(db, TDBSAM_VERSION_STRING,
205                                TDBSAM_VERSION) != 0) {
206                 DEBUG(0, ("Could not store tdbsam version\n"));
207                 goto cancel;
208         }
209
210         if (db->transaction_commit(db) != 0) {
211                 DEBUG(0, ("Could not commit transaction\n"));
212                 return false;
213         }
214
215         return true;
216
217  cancel:
218         if (db->transaction_cancel(db) != 0) {
219                 smb_panic("transaction_cancel failed");
220         }
221
222         return false;
223 }
224
225 /*********************************************************************
226  Open the tdbsam file based on the absolute path specified.
227  Uses a reference count to allow multiple open calls.
228 *********************************************************************/
229
230 static bool tdbsam_open( const char *name )
231 {
232         int32   version;
233
234         /* check if we are already open */
235
236         if ( db_sam ) {
237                 return true;
238         }
239
240         /* Try to open tdb passwd.  Create a new one if necessary */
241
242         db_sam = db_open(NULL, name, 0, TDB_DEFAULT, O_CREAT|O_RDWR, 0600);
243         if (db_sam == NULL) {
244                 DEBUG(0, ("tdbsam_open: Failed to open/create TDB passwd "
245                           "[%s]\n", name));
246                 return false;
247         }
248
249         /* Check the version */
250         version = dbwrap_fetch_int32(db_sam, TDBSAM_VERSION_STRING);
251         if (version == -1) {
252                 version = 0;    /* Version not found, assume version 0 */
253         }
254
255         /* Compare the version */
256         if (version > TDBSAM_VERSION) {
257                 /* Version more recent than the latest known */
258                 DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
259                 TALLOC_FREE(db_sam);
260                 return false;
261         }
262
263         if ( version < TDBSAM_VERSION ) {
264                 DEBUG(1, ("tdbsam_open: Converting version %d database to "
265                           "version %d.\n", version, TDBSAM_VERSION));
266
267                 if ( !tdbsam_convert(db_sam, version) ) {
268                         DEBUG(0, ("tdbsam_open: Error when trying to convert "
269                                   "tdbsam [%s]\n",name));
270                         TALLOC_FREE(db_sam);
271                         return false;
272                 }
273
274                 DEBUG(3, ("TDBSAM converted successfully.\n"));
275         }
276
277         DEBUG(4,("tdbsam_open: successfully opened %s\n", name ));
278
279         return true;
280 }
281
282 /******************************************************************
283  Lookup a name in the SAM TDB
284 ******************************************************************/
285
286 static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods,
287                                     struct samu *user, const char *sname)
288 {
289         TDB_DATA        data;
290         fstring         keystr;
291         fstring         name;
292
293         if ( !user ) {
294                 DEBUG(0,("pdb_getsampwnam: struct samu is NULL.\n"));
295                 return NT_STATUS_NO_MEMORY;
296         }
297
298         /* Data is stored in all lower-case */
299         fstrcpy(name, sname);
300         strlower_m(name);
301
302         /* set search key */
303         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
304
305         /* open the database */
306
307         if ( !tdbsam_open( tdbsam_filename ) ) {
308                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
309                 return NT_STATUS_ACCESS_DENIED;
310         }
311
312         /* get the record */
313
314         data = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr);
315         if (!data.dptr) {
316                 DEBUG(5,("pdb_getsampwnam (TDB): error fetching database.\n"));
317                 DEBUGADD(5, (" Key: %s\n", keystr));
318                 return NT_STATUS_NO_SUCH_USER;
319         }
320
321         /* unpack the buffer */
322
323         if (!init_samu_from_buffer(user, SAMU_BUFFER_LATEST, data.dptr, data.dsize)) {
324                 DEBUG(0,("pdb_getsampwent: Bad struct samu entry returned from TDB!\n"));
325                 SAFE_FREE(data.dptr);
326                 return NT_STATUS_NO_MEMORY;
327         }
328
329         /* success */
330
331         TALLOC_FREE(data.dptr);
332
333         return NT_STATUS_OK;
334 }
335
336 /***************************************************************************
337  Search by rid
338  **************************************************************************/
339
340 static NTSTATUS tdbsam_getsampwrid (struct pdb_methods *my_methods,
341                                     struct samu *user, uint32 rid)
342 {
343         NTSTATUS                nt_status = NT_STATUS_UNSUCCESSFUL;
344         TDB_DATA                data;
345         fstring                 keystr;
346         fstring                 name;
347
348         if ( !user ) {
349                 DEBUG(0,("pdb_getsampwrid: struct samu is NULL.\n"));
350                 return nt_status;
351         }
352
353         /* set search key */
354
355         slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
356
357         /* open the database */
358
359         if ( !tdbsam_open( tdbsam_filename ) ) {
360                 DEBUG(0,("tdbsam_getsampwrid: failed to open %s!\n", tdbsam_filename));
361                 return NT_STATUS_ACCESS_DENIED;
362         }
363
364         /* get the record */
365
366         data = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr);
367         if (!data.dptr) {
368                 DEBUG(5,("pdb_getsampwrid (TDB): error looking up RID %d by key %s.\n", rid, keystr));
369                 return NT_STATUS_UNSUCCESSFUL;
370         }
371
372         fstrcpy(name, (const char *)data.dptr);
373         TALLOC_FREE(data.dptr);
374
375         return tdbsam_getsampwnam (my_methods, user, name);
376 }
377
378 static NTSTATUS tdbsam_getsampwsid(struct pdb_methods *my_methods,
379                                    struct samu * user, const DOM_SID *sid)
380 {
381         uint32 rid;
382
383         if ( !sid_peek_check_rid(get_global_sam_sid(), sid, &rid) )
384                 return NT_STATUS_UNSUCCESSFUL;
385
386         return tdbsam_getsampwrid(my_methods, user, rid);
387 }
388
389 static bool tdb_delete_samacct_only( struct samu *sam_pass )
390 {
391         fstring         keystr;
392         fstring         name;
393         NTSTATUS status;
394
395         fstrcpy(name, pdb_get_username(sam_pass));
396         strlower_m(name);
397
398         /* set the search key */
399
400         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
401
402         /* it's outaa here!  8^) */
403         if ( !tdbsam_open( tdbsam_filename ) ) {
404                 DEBUG(0,("tdb_delete_samacct_only: failed to open %s!\n",
405                          tdbsam_filename));
406                 return false;
407         }
408
409         status = dbwrap_delete_bystring(db_sam, keystr);
410         if (!NT_STATUS_IS_OK(status)) {
411                 DEBUG(5, ("Error deleting entry from tdb passwd "
412                           "database: %s!\n", nt_errstr(status)));
413                 return false;
414         }
415
416         return true;
417 }
418
419 /***************************************************************************
420  Delete a struct samu records for the username and RID key
421 ****************************************************************************/
422
423 static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods,
424                                           struct samu *sam_pass)
425 {
426         NTSTATUS        nt_status = NT_STATUS_UNSUCCESSFUL;
427         fstring         keystr;
428         uint32          rid;
429         fstring         name;
430
431         /* open the database */
432
433         if ( !tdbsam_open( tdbsam_filename ) ) {
434                 DEBUG(0,("tdbsam_delete_sam_account: failed to open %s!\n",
435                          tdbsam_filename));
436                 return NT_STATUS_ACCESS_DENIED;
437         }
438
439         fstrcpy(name, pdb_get_username(sam_pass));
440         strlower_m(name);
441
442         /* set the search key */
443
444         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
445
446         rid = pdb_get_user_rid(sam_pass);
447
448         /* it's outaa here!  8^) */
449
450         if (db_sam->transaction_start(db_sam) != 0) {
451                 DEBUG(0, ("Could not start transaction\n"));
452                 return NT_STATUS_UNSUCCESSFUL;
453         }
454
455         nt_status = dbwrap_delete_bystring(db_sam, keystr);
456         if (!NT_STATUS_IS_OK(nt_status)) {
457                 DEBUG(5, ("Error deleting entry from tdb passwd "
458                           "database: %s!\n", nt_errstr(nt_status)));
459                 goto cancel;
460         }
461
462         /* set the search key */
463
464         slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
465
466         /* it's outaa here!  8^) */
467
468         nt_status = dbwrap_delete_bystring(db_sam, keystr);
469         if (!NT_STATUS_IS_OK(nt_status)) {
470                 DEBUG(5, ("Error deleting entry from tdb rid "
471                           "database: %s!\n", nt_errstr(nt_status)));
472                 goto cancel;
473         }
474
475         if (db_sam->transaction_commit(db_sam) != 0) {
476                 DEBUG(0, ("Could not commit transaction\n"));
477                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
478         }
479
480         return NT_STATUS_OK;
481
482  cancel:
483         if (db_sam->transaction_cancel(db_sam) != 0) {
484                 smb_panic("transaction_cancel failed");
485         }
486
487         return nt_status;
488 }
489
490
491 /***************************************************************************
492  Update the TDB SAM account record only
493  Assumes that the tdbsam is already open 
494 ****************************************************************************/
495 static bool tdb_update_samacct_only( struct samu* newpwd, int flag )
496 {
497         TDB_DATA        data;
498         uint8           *buf = NULL;
499         fstring         keystr;
500         fstring         name;
501         bool            ret = false;
502         NTSTATUS status;
503
504         /* copy the struct samu struct into a BYTE buffer for storage */
505
506         if ( (data.dsize=init_buffer_from_samu(&buf, newpwd, False)) == -1 ) {
507                 DEBUG(0,("tdb_update_sam: ERROR - Unable to copy struct samu info BYTE buffer!\n"));
508                 goto done;
509         }
510         data.dptr = buf;
511
512         fstrcpy(name, pdb_get_username(newpwd));
513         strlower_m(name);
514
515         DEBUG(5, ("Storing %saccount %s with RID %d\n",
516                   flag == TDB_INSERT ? "(new) " : "", name,
517                   pdb_get_user_rid(newpwd)));
518
519         /* setup the USER index key */
520         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
521
522         /* add the account */
523
524         status = dbwrap_store_bystring(db_sam, keystr, data, flag);
525         if (!NT_STATUS_IS_OK(status)) {
526                 DEBUG(0, ("Unable to modify passwd TDB: %s!",
527                           nt_errstr(status)));
528                 goto done;
529         }
530
531         ret = true;
532
533 done:
534         /* cleanup */
535         SAFE_FREE(buf);
536         return ret;
537 }
538
539 /***************************************************************************
540  Update the TDB SAM RID record only
541  Assumes that the tdbsam is already open
542 ****************************************************************************/
543 static bool tdb_update_ridrec_only( struct samu* newpwd, int flag )
544 {
545         TDB_DATA        data;
546         fstring         keystr;
547         fstring         name;
548         NTSTATUS status;
549
550         fstrcpy(name, pdb_get_username(newpwd));
551         strlower_m(name);
552
553         /* setup RID data */
554         data = string_term_tdb_data(name);
555
556         /* setup the RID index key */
557         slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX,
558                  pdb_get_user_rid(newpwd));
559
560         /* add the reference */
561         status = dbwrap_store_bystring(db_sam, keystr, data, flag);
562         if (!NT_STATUS_IS_OK(status)) {
563                 DEBUG(0, ("Unable to modify TDB passwd: %s!\n",
564                           nt_errstr(status)));
565                 return false;
566         }
567
568         return true;
569
570 }
571
572 /***************************************************************************
573  Update the TDB SAM
574 ****************************************************************************/
575
576 static bool tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd,
577                            int flag)
578 {
579         if (!pdb_get_user_rid(newpwd)) {
580                 DEBUG(0,("tdb_update_sam: struct samu (%s) with no RID!\n",
581                          pdb_get_username(newpwd)));
582                 return False;
583         }
584
585         /* open the database */
586
587         if ( !tdbsam_open( tdbsam_filename ) ) {
588                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
589                 return False;
590         }
591
592         if (db_sam->transaction_start(db_sam) != 0) {
593                 DEBUG(0, ("Could not start transaction\n"));
594                 return false;
595         }
596
597         if (!tdb_update_samacct_only(newpwd, flag)
598             || !tdb_update_ridrec_only(newpwd, flag)) {
599                 goto cancel;
600         }
601
602         if (db_sam->transaction_commit(db_sam) != 0) {
603                 DEBUG(0, ("Could not commit transaction\n"));
604                 return false;
605         }
606
607         return true;
608
609  cancel:
610         if (db_sam->transaction_cancel(db_sam) != 0) {
611                 smb_panic("transaction_cancel failed");
612         }
613         return false;
614 }
615
616 /***************************************************************************
617  Modifies an existing struct samu
618 ****************************************************************************/
619
620 static NTSTATUS tdbsam_update_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
621 {
622         if ( !tdb_update_sam(my_methods, newpwd, TDB_MODIFY) )
623                 return NT_STATUS_UNSUCCESSFUL;
624         
625         return NT_STATUS_OK;
626 }
627
628 /***************************************************************************
629  Adds an existing struct samu
630 ****************************************************************************/
631
632 static NTSTATUS tdbsam_add_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
633 {
634         if ( !tdb_update_sam(my_methods, newpwd, TDB_INSERT) )
635                 return NT_STATUS_UNSUCCESSFUL;
636                 
637         return NT_STATUS_OK;
638 }
639
640 /***************************************************************************
641  Renames a struct samu
642  - check for the posix user/rename user script
643  - Add and lock the new user record
644  - rename the posix user
645  - rewrite the rid->username record
646  - delete the old user
647  - unlock the new user record
648 ***************************************************************************/
649 static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
650                                           struct samu *old_acct,
651                                           const char *newname)
652 {
653         struct samu      *new_acct = NULL;
654         char *rename_script = NULL;
655         int              rename_ret;
656         fstring          oldname_lower;
657         fstring          newname_lower;
658
659         /* can't do anything without an external script */
660
661         if ( !(new_acct = samu_new( talloc_tos() )) ) {
662                 return NT_STATUS_NO_MEMORY;
663         }
664
665         rename_script = talloc_strdup(new_acct, lp_renameuser_script());
666         if (!rename_script) {
667                 TALLOC_FREE(new_acct);
668                 return NT_STATUS_NO_MEMORY;
669         }
670         if (!*rename_script) {
671                 TALLOC_FREE(new_acct);
672                 return NT_STATUS_ACCESS_DENIED;
673         }
674
675         if ( !pdb_copy_sam_account(new_acct, old_acct)
676                 || !pdb_set_username(new_acct, newname, PDB_CHANGED))
677         {
678                 TALLOC_FREE(new_acct);
679                 return NT_STATUS_NO_MEMORY;
680         }
681
682         /* open the database */
683         if ( !tdbsam_open( tdbsam_filename ) ) {
684                 DEBUG(0, ("tdbsam_getsampwnam: failed to open %s!\n",
685                           tdbsam_filename));
686                 TALLOC_FREE(new_acct);
687                 return NT_STATUS_ACCESS_DENIED;
688         }
689
690         if (db_sam->transaction_start(db_sam) != 0) {
691                 DEBUG(0, ("Could not start transaction\n"));
692                 TALLOC_FREE(new_acct);
693                 return NT_STATUS_ACCESS_DENIED;
694
695         }
696
697         /* add the new account and lock it */
698         if ( !tdb_update_samacct_only(new_acct, TDB_INSERT) ) {
699                 goto cancel;
700         }
701
702         /* Rename the posix user.  Follow the semantics of _samr_create_user()
703            so that we lower case the posix name but preserve the case in passdb */
704
705         fstrcpy( oldname_lower, pdb_get_username(old_acct) );
706         strlower_m( oldname_lower );
707
708         fstrcpy( newname_lower, newname );
709         strlower_m( newname_lower );
710
711         rename_script = talloc_string_sub2(new_acct,
712                                 rename_script,
713                                 "%unew",
714                                 newname_lower,
715                                 true,
716                                 false,
717                                 true);
718         if (!rename_script) {
719                 goto cancel;
720         }
721         rename_script = talloc_string_sub2(new_acct,
722                                 rename_script,
723                                 "%uold",
724                                 oldname_lower,
725                                 true,
726                                 false,
727                                 true);
728         if (!rename_script) {
729                 goto cancel;
730         }
731         rename_ret = smbrun(rename_script, NULL);
732
733         DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n",
734                                 rename_script, rename_ret));
735
736         if (rename_ret != 0) {
737                 goto cancel;
738         }
739
740         smb_nscd_flush_user_cache();
741
742         /* rewrite the rid->username record */
743
744         if ( !tdb_update_ridrec_only( new_acct, TDB_MODIFY) ) {
745                 goto cancel;
746         }
747
748         tdb_delete_samacct_only( old_acct );
749
750         if (db_sam->transaction_commit(db_sam) != 0) {
751                 /*
752                  * Ok, we're screwed. We've changed the posix account, but
753                  * could not adapt passdb.tdb. Shall we change the posix
754                  * account back?
755                  */
756                 DEBUG(0, ("transaction_commit failed\n"));
757                 TALLOC_FREE(new_acct);
758                 return NT_STATUS_INTERNAL_DB_CORRUPTION;        
759         }
760
761         TALLOC_FREE(new_acct );
762         return NT_STATUS_OK;
763
764  cancel:
765         if (db_sam->transaction_cancel(db_sam) != 0) {
766                 smb_panic("transaction_cancel failed");
767         }
768
769         TALLOC_FREE(new_acct);
770
771         return NT_STATUS_ACCESS_DENIED; 
772 }
773
774 static bool tdbsam_rid_algorithm(struct pdb_methods *methods)
775 {
776         return False;
777 }
778
779 static bool tdbsam_new_rid(struct pdb_methods *methods, uint32 *prid)
780 {
781         uint32 rid;
782
783         rid = BASE_RID;         /* Default if not set */
784
785         if (!tdbsam_open(tdbsam_filename)) {
786                 DEBUG(0,("tdbsam_new_rid: failed to open %s!\n",
787                         tdbsam_filename));
788                 return false;
789         }
790
791         if (dbwrap_change_uint32_atomic(db_sam, NEXT_RID_STRING, &rid, 1) != 0) {
792                 DEBUG(3, ("tdbsam_new_rid: Failed to increase %s\n",
793                         NEXT_RID_STRING));
794                 return false;
795         }
796
797         *prid = rid;
798
799         return true;
800 }
801
802 struct tdbsam_search_state {
803         struct pdb_methods *methods;
804         uint32_t acct_flags;
805
806         uint32_t *rids;
807         uint32_t num_rids;
808         ssize_t array_size;
809         uint32_t current;
810 };
811
812 static int tdbsam_collect_rids(struct db_record *rec, void *private_data)
813 {
814         struct tdbsam_search_state *state = talloc_get_type_abort(
815                 private_data, struct tdbsam_search_state);
816         size_t prefixlen = strlen(RIDPREFIX);
817         uint32 rid;
818
819         if ((rec->key.dsize < prefixlen)
820             || (strncmp((char *)rec->key.dptr, RIDPREFIX, prefixlen))) {
821                 return 0;
822         }
823
824         rid = strtoul((char *)rec->key.dptr+prefixlen, NULL, 16);
825
826         ADD_TO_LARGE_ARRAY(state, uint32, rid, &state->rids, &state->num_rids,
827                            &state->array_size);
828
829         return 0;
830 }
831
832 static void tdbsam_search_end(struct pdb_search *search)
833 {
834         struct tdbsam_search_state *state = talloc_get_type_abort(
835                 search->private_data, struct tdbsam_search_state);
836         TALLOC_FREE(state);
837 }
838
839 static bool tdbsam_search_next_entry(struct pdb_search *search,
840                                      struct samr_displayentry *entry)
841 {
842         struct tdbsam_search_state *state = talloc_get_type_abort(
843                 search->private_data, struct tdbsam_search_state);
844         struct samu *user = NULL;
845         NTSTATUS status;
846         uint32_t rid;
847
848  again:
849         TALLOC_FREE(user);
850         user = samu_new(talloc_tos());
851         if (user == NULL) {
852                 DEBUG(0, ("samu_new failed\n"));
853                 return false;
854         }
855
856         if (state->current == state->num_rids) {
857                 return false;
858         }
859
860         rid = state->rids[state->current++];
861
862         status = tdbsam_getsampwrid(state->methods, user, rid);
863
864         if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
865                 /*
866                  * Someone has deleted that user since we listed the RIDs
867                  */
868                 goto again;
869         }
870
871         if (!NT_STATUS_IS_OK(status)) {
872                 DEBUG(10, ("tdbsam_getsampwrid failed: %s\n",
873                            nt_errstr(status)));
874                 TALLOC_FREE(user);
875                 return false;
876         }
877
878         if ((state->acct_flags != 0) &&
879             ((state->acct_flags & pdb_get_acct_ctrl(user)) == 0)) {
880                 goto again;
881         }
882
883         entry->acct_flags = pdb_get_acct_ctrl(user);
884         entry->rid = rid;
885         entry->account_name = talloc_strdup(
886                 search->mem_ctx, pdb_get_username(user));
887         entry->fullname = talloc_strdup(
888                 search->mem_ctx, pdb_get_fullname(user));
889         entry->description = talloc_strdup(
890                 search->mem_ctx, pdb_get_acct_desc(user));
891
892         TALLOC_FREE(user);
893
894         if ((entry->account_name == NULL) || (entry->fullname == NULL)
895             || (entry->description == NULL)) {
896                 DEBUG(0, ("talloc_strdup failed\n"));
897                 return false;
898         }
899
900         return true;
901 }
902
903 static bool tdbsam_search_users(struct pdb_methods *methods,
904                                 struct pdb_search *search,
905                                 uint32 acct_flags)
906 {
907         struct tdbsam_search_state *state;
908
909         if (!tdbsam_open(tdbsam_filename)) {
910                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n",
911                          tdbsam_filename));
912                 return false;
913         }
914
915         state = TALLOC_ZERO_P(search->mem_ctx, struct tdbsam_search_state);
916         if (state == NULL) {
917                 DEBUG(0, ("talloc failed\n"));
918                 return false;
919         }
920         state->acct_flags = acct_flags;
921         state->methods = methods;
922
923         db_sam->traverse_read(db_sam, tdbsam_collect_rids, state);
924
925         search->private_data = state;
926         search->next_entry = tdbsam_search_next_entry;
927         search->search_end = tdbsam_search_end;
928
929         return true;
930 }
931
932 /*********************************************************************
933  Initialize the tdb sam backend.  Setup the dispath table of methods,
934  open the tdb, etc...
935 *********************************************************************/
936
937 static NTSTATUS pdb_init_tdbsam(struct pdb_methods **pdb_method, const char *location)
938 {
939         NTSTATUS nt_status;
940         char *tdbfile = NULL;
941         const char *pfile = location;
942
943         if (!NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method ))) {
944                 return nt_status;
945         }
946
947         (*pdb_method)->name = "tdbsam";
948
949         (*pdb_method)->getsampwnam = tdbsam_getsampwnam;
950         (*pdb_method)->getsampwsid = tdbsam_getsampwsid;
951         (*pdb_method)->add_sam_account = tdbsam_add_sam_account;
952         (*pdb_method)->update_sam_account = tdbsam_update_sam_account;
953         (*pdb_method)->delete_sam_account = tdbsam_delete_sam_account;
954         (*pdb_method)->rename_sam_account = tdbsam_rename_sam_account;
955         (*pdb_method)->search_users = tdbsam_search_users;
956
957         (*pdb_method)->rid_algorithm = tdbsam_rid_algorithm;
958         (*pdb_method)->new_rid = tdbsam_new_rid;
959
960         /* save the path for later */
961
962         if (!location) {
963                 if (asprintf(&tdbfile, "%s/%s", lp_private_dir(),
964                              PASSDB_FILE_NAME) < 0) {
965                         return NT_STATUS_NO_MEMORY;
966                 }
967                 pfile = tdbfile;
968         }
969         tdbsam_filename = SMB_STRDUP(pfile);
970         if (!tdbsam_filename) {
971                 return NT_STATUS_NO_MEMORY;
972         }
973         SAFE_FREE(tdbfile);
974
975         /* no private data */
976
977         (*pdb_method)->private_data      = NULL;
978         (*pdb_method)->free_private_data = NULL;
979
980         return NT_STATUS_OK;
981 }
982
983 NTSTATUS pdb_tdbsam_init(void)
984 {
985         return smb_register_passdb(PASSDB_INTERFACE_VERSION, "tdbsam", pdb_init_tdbsam);
986 }