source: branches/samba-3.3.x/source/passdb/pdb_tdb.c

Last change on this file was 224, checked in by Herwig Bauernfeind, 16 years ago

Update Samba 3.3 branch to 3.3.4

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