source: trunk/server/source3/passdb/pdb_tdb.c

Last change on this file was 745, checked in by Silvan Scherrer, 13 years ago

Samba Server: updated trunk to 3.6.0

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