2 * Unix SMB/CIFS implementation.
3 * tdbsam2 - sam backend
4 * Copyright (C) Simo Sorce 2002-2003
6 * This program is free software; you can redistribute it and/or modify it under
7 * the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * You should have received a copy of the GNU General Public License along with
17 * this program; if not, write to the Free Software Foundation, Inc., 675
18 * Mass Ave, Cambridge, MA 02139, USA.
23 #include "tdbsam2_parse_info.h"
26 static int gums_tdbsam2_debug_class
= DBGC_ALL
;
30 #define DBGC_CLASS gums_tdbsam2_debug_class
33 #define TDBSAM_VERSION 20021215
34 #define TDB_FILE_NAME "tdbsam2.tdb"
35 #define NAMEPREFIX "NAME_"
36 #define SIDPREFIX "SID_"
37 #define PRIVILEGEPREFIX "PRIV_"
39 #define TDB_FORMAT_STRING "ddB"
41 #define TALLOC_CHECK(ptr, err, label) do { if ((ptr) == NULL) { DEBUG(0, ("%s: Out of memory!\n", FUNCTION_MACRO)); err = NT_STATUS_NO_MEMORY; goto label; } } while(0)
42 #define SET_OR_FAIL(func, label) do { if (!NT_STATUS_IS_OK(func)) { DEBUG(0, ("%s: Setting gums object data failed!\n", FUNCTION_MACRO)); goto label; } } while(0)
46 struct tdbsam2_enum_objs
{
51 struct tdbsam2_enum_objs
*next
;
55 struct tdbsam2_domain_data
*domain
;
56 struct tdbsam2_user_data
*user
;
57 struct tdbsam2_group_data
*group
;
58 struct tdbsam2_priv_data
*priv
;
61 struct tdbsam2_object
{
64 union tdbsam2_data data
;
67 struct tdbsam2_private_data
{
70 struct tdbsam2_enum_objs
*teo_handlers
;
73 static struct tdbsam2_private_data
*ts2_privs
;
76 static NTSTATUS
init_object_from_buffer(GUMS_OBJECT
**go
, char *buffer
, int size
)
79 NTSTATUS ret
= NT_STATUS_UNSUCCESSFUL
;
82 char *obj_data
= NULL
;
87 mem_ctx
= talloc_init("init_object_from_buffer");
89 DEBUG(0, ("init_object_from_buffer: Out of memory!\n"));
90 return NT_STATUS_NO_MEMORY
;
93 len
= tdb_unpack (buffer
, size
, TDB_FORMAT_STRING
,
96 &data_size
, &obj_data
);
98 if (len
== -1 || data_size
<= 0)
101 /* version is checked inside this function so that backward compatibility code can be
103 this way we can easily handle database format upgrades */
104 if (version
!= TDBSAM_VERSION
) {
105 DEBUG(3,("init_tdbsam2_object_from_buffer: Error, db object has wrong tdbsam version!\n"));
109 /* be sure the string is terminated before trying to parse it */
110 if (obj_data
[data_size
- 1] != '\0')
111 obj_data
[data_size
- 1] = '\0';
113 *go
= (GUMS_OBJECT
*)talloc_zero(mem_ctx
, sizeof(GUMS_OBJECT
));
114 TALLOC_CHECK(*go
, ret
, done
);
118 case GUMS_OBJ_DOMAIN
:
119 iret
= gen_parse(mem_ctx
, pinfo_tdbsam2_domain_data
, (char *)(*go
), obj_data
);
124 iret
= gen_parse(mem_ctx
, pinfo_tdbsam2_group_data
, (char *)(*go
), obj_data
);
127 case GUMS_OBJ_NORMAL_USER
:
128 iret
= gen_parse(mem_ctx
, pinfo_tdbsam2_user_data
, (char *)(*go
), obj_data
);
131 case GUMS_OBJ_PRIVILEGE
:
132 iret
= gen_parse(mem_ctx
, pinfo_tdbsam2_priv_data
, (char *)(*go
), obj_data
);
136 DEBUG(3,("init_object_from_buffer: Error, wrong object type number!\n"));
141 DEBUG(0, ("init_object_from_buffer: Fatal Error! Unable to parse object!\n"));
142 DEBUG(0, ("init_object_from_buffer: DB Corrupt ?"));
146 (*go
)->mem_ctx
= mem_ctx
;
154 static NTSTATUS
init_buffer_from_object(char **buffer
, size_t *len
, TALLOC_CTX
*mem_ctx
, GUMS_OBJECT
*object
)
162 return NT_STATUS_INVALID_PARAMETER
;
164 switch (gums_get_object_type(object
)) {
166 case GUMS_OBJ_DOMAIN
:
167 genbuf
= gen_dump(mem_ctx
, pinfo_tdbsam2_domain_data
, (char *)object
, 0);
172 genbuf
= gen_dump(mem_ctx
, pinfo_tdbsam2_group_data
, (char *)object
, 0);
175 case GUMS_OBJ_NORMAL_USER
:
176 genbuf
= gen_dump(mem_ctx
, pinfo_tdbsam2_user_data
, (char *)object
, 0);
179 case GUMS_OBJ_PRIVILEGE
:
180 genbuf
= gen_dump(mem_ctx
, pinfo_tdbsam2_priv_data
, (char *)object
, 0);
184 DEBUG(3,("init_buffer_from_object: Error, wrong object type number!\n"));
185 return NT_STATUS_UNSUCCESSFUL
;
188 if (genbuf
== NULL
) {
189 DEBUG(0, ("init_buffer_from_object: Fatal Error! Unable to dump object!\n"));
190 return NT_STATUS_UNSUCCESSFUL
;
193 buflen
= tdb_pack(NULL
, 0, TDB_FORMAT_STRING
,
196 strlen(genbuf
) + 1, genbuf
);
198 *buffer
= talloc(mem_ctx
, buflen
);
199 TALLOC_CHECK(*buffer
, ret
, done
);
201 *len
= tdb_pack(*buffer
, buflen
, TDB_FORMAT_STRING
,
204 strlen(genbuf
) + 1, genbuf
);
206 if (*len
!= buflen
) {
207 DEBUG(0, ("init_buffer_from_object: something odd is going on here: bufflen (%d) != len (%d) in tdb_pack operations!\n",
210 ret
= NT_STATUS_UNSUCCESSFUL
;
219 static NTSTATUS
opentdb(TDB_CONTEXT
**tdb
, BOOL readonly
)
222 return NT_STATUS_INVALID_PARAMETER
;
224 *tdb
= tdb_open_log(ts2_privs
->storage
, 0, TDB_DEFAULT
, readonly
?(O_RDONLY
):(O_RDWR
| O_CREAT
), 0600);
227 DEBUG(0, ("opentdb: Unable to open database (%s)!\n", ts2_privs
->storage
));
228 return NT_STATUS_UNSUCCESSFUL
;
234 static NTSTATUS
get_object_by_sid(TDB_CONTEXT
*tdb
, GUMS_OBJECT
**obj
, const DOM_SID
*sid
)
241 return NT_STATUS_INVALID_PARAMETER
;
243 slprintf(keystr
, sizeof(keystr
)-1, "%s%s", SIDPREFIX
, sid_string_static(sid
));
245 key
.dsize
= strlen(keystr
) + 1;
247 data
= tdb_fetch(tdb
, key
);
249 DEBUG(5, ("get_object_by_sid: Entry not found!\n"));
250 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdb
)));
251 DEBUGADD(5, (" Key: %s\n", keystr
));
252 ret
= NT_STATUS_NOT_FOUND
;
256 if (!NT_STATUS_IS_OK(init_object_from_buffer(obj
, data
.dptr
, data
.dsize
))) {
257 DEBUG(0, ("get_object_by_sid: Error fetching database, malformed entry!\n"));
258 ret
= NT_STATUS_UNSUCCESSFUL
;
265 SAFE_FREE(data
.dptr
);
269 static NTSTATUS
get_object_by_name(TDB_CONTEXT
*tdb
, GUMS_OBJECT
**obj
, const char* name
)
272 NTSTATUS ret
= NT_STATUS_OK
;
281 return NT_STATUS_INVALID_PARAMETER
;
283 /* Data is stored in all lower-case */
284 fstrcpy(objname
, name
);
287 slprintf(keystr
, sizeof(keystr
)-1, "%s%s", NAMEPREFIX
, objname
);
289 key
.dsize
= strlen(keystr
) + 1;
291 data
= tdb_fetch(tdb
, key
);
293 DEBUG(5, ("get_object_by_name: Entry not found!\n"));
294 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdb
)));
295 DEBUGADD(5, (" Key: %s\n", keystr
));
296 ret
= NT_STATUS_NOT_FOUND
;
300 fstrcpy(sidstr
, data
.dptr
);
301 sidstr_len
= data
.dsize
;
303 SAFE_FREE(data
.dptr
);
305 if (sidstr_len
<= 0) {
306 DEBUG(5, ("get_object_by_name: Error unpacking database object!\n"));
307 ret
= NT_STATUS_UNSUCCESSFUL
;
311 if (!string_to_sid(&sid
, sidstr
)) {
312 DEBUG(5, ("get_object_by_name: Error invalid sid string found in database object!\n"));
313 ret
= NT_STATUS_UNSUCCESSFUL
;
318 if (NT_STATUS_IS_OK(ret
))
319 return get_object_by_sid(tdb
, obj
, &sid
);
323 /* store a tdbsam2_object
324 * flag: TDB_REPLACE or TDB_MODIFY or TDB_INSERT
327 static NTSTATUS
store_object(TDB_CONTEXT
*tdb
, const GUMS_OBJECT
*object
, int flag
)
330 NTSTATUS ret
= NT_STATUS_OK
;
331 TDB_DATA data
, data2
, key
, key2
;
339 /* TODO: on object renaming/replacing this function should
340 * check name->sid record and delete the old one
343 mem_ctx
= talloc_init("store_object");
345 DEBUG(0, ("store_object: Out of memory!\n"));
346 return NT_STATUS_NO_MEMORY
;
349 if (!NT_STATUS_IS_OK(ret
= init_buffer_from_object(&(data
.dptr
), &(data
.dsize
), mem_ctx
, object
)))
352 switch (object
->type
) {
354 case GUMS_OBJ_DOMAIN
:
357 case GUMS_OBJ_NORMAL_USER
:
359 fstrcpy(sidstr
, sid_string_static(gums_get_object_sid(object
)));
360 slprintf(keystr
, sizeof(keystr
) - 1, "%s%s", SIDPREFIX
, sidstr
);
364 ret
= NT_STATUS_UNSUCCESSFUL
;
368 /* Data is stored in all lower-case */
369 fstrcpy(objname
, gums_get_object_name(object
));
372 slprintf(namestr
, sizeof(namestr
) - 1, "%s%s", NAMEPREFIX
, objname
);
374 if (object
->type
!= GUMS_OBJ_PRIVILEGE
) {
376 key
.dsize
= strlen(keystr
) + 1;
378 if ((r
= tdb_store(tdb
, key
, data
, flag
)) != TDB_SUCCESS
) {
379 DEBUG(0, ("store_object: Unable to modify TDBSAM!\n"));
380 DEBUGADD(0, (" Error: %s", tdb_errorstr(tdb
)));
381 DEBUGADD(0, (" occured while storing sid record (%s)\n", keystr
));
382 if (r
== TDB_ERR_EXISTS
)
383 ret
= NT_STATUS_UNSUCCESSFUL
;
385 ret
= NT_STATUS_INTERNAL_DB_ERROR
;
390 data2
.dsize
= strlen(sidstr
) + 1;
392 key2
.dsize
= strlen(namestr
) + 1;
394 if ((r
= tdb_store(tdb
, key2
, data2
, flag
)) != TDB_SUCCESS
) {
395 DEBUG(0, ("store_object: Unable to modify TDBSAM!\n"));
396 DEBUGADD(0, (" Error: %s", tdb_errorstr(tdb
)));
397 DEBUGADD(0, (" occured while storing name record (%s)\n", keystr
));
398 DEBUGADD(0, (" attempting rollback operation.\n"));
399 if ((tdb_delete(tdb
, key
)) != TDB_SUCCESS
) {
400 DEBUG(0, ("store_object: Unable to rollback! Check database consitency!\n"));
402 if (r
== TDB_ERR_EXISTS
)
403 ret
= NT_STATUS_UNSUCCESSFUL
;
405 ret
= NT_STATUS_INTERNAL_DB_ERROR
;
410 key
.dsize
= strlen(keystr
) + 1;
412 if ((r
= tdb_store(tdb
, key
, data
, flag
)) != TDB_SUCCESS
) {
413 DEBUG(0, ("store_object: Unable to modify TDBSAM!\n"));
414 DEBUGADD(0, (" Error: %s", tdb_errorstr(tdb
)));
415 DEBUGADD(0, (" occured while storing sid record (%s)\n", keystr
));
416 if (r
== TDB_ERR_EXISTS
)
417 ret
= NT_STATUS_UNSUCCESSFUL
;
419 ret
= NT_STATUS_INTERNAL_DB_ERROR
;
424 /* TODO: update the general database counter */
425 /* TODO: update this entry counter too */
428 talloc_destroy(mem_ctx
);
433 static NTSTATUS
user_data_to_gums_object(GUMS_OBJECT
**object
, struct tdbsam2_user_data
*userdata
)
435 NTSTATUS ret
= NT_STATUS_UNSUCCESSFUL
;
438 if (!object
|| !userdata
) {
439 DEBUG(0, ("tdbsam2_user_data_to_gums_object: no NULL pointers are accepted here!\n"));
443 /* userdata->xcounter */
444 /* userdata->sec_desc */
446 SET_OR_FAIL(gums_set_object_sid(*object
, userdata
->user_sid
), error
);
447 SET_OR_FAIL(gums_set_object_name(*object
, userdata
->name
), error
);
449 SET_OR_FAIL(gums_set_user_pri_group(*object
, userdata
->group_sid
), error
);
451 if (userdata
->description
)
452 SET_OR_FAIL(gums_set_object_description(*object
, userdata
->description
), error
);
454 if (userdata
->full_name
)
455 SET_OR_FAIL(gums_set_user_fullname(*object
, userdata
->full_name
), error
);
457 if (userdata
->home_dir
)
458 SET_OR_FAIL(gums_set_user_homedir(*object
, userdata
->home_dir
), error
);
460 if (userdata
->dir_drive
)
461 SET_OR_FAIL(gums_set_user_dir_drive(*object
, userdata
->dir_drive
), error
);
463 if (userdata
->logon_script
)
464 SET_OR_FAIL(gums_set_user_logon_script(*object
, userdata
->logon_script
), error
);
466 if (userdata
->profile_path
)
467 SET_OR_FAIL(gums_set_user_profile_path(*object
, userdata
->profile_path
), error
);
469 if (userdata
->workstations
)
470 SET_OR_FAIL(gums_set_user_workstations(*object
, userdata
->workstations
), error
);
472 if (userdata
->unknown_str
)
473 SET_OR_FAIL(gums_set_user_unknown_str(*object
, userdata
->unknown_str
), error
);
475 if (userdata
->munged_dial
)
476 SET_OR_FAIL(gums_set_user_munged_dial(*object
, userdata
->munged_dial
), error
);
478 SET_OR_FAIL(gums_set_user_logon_divs(*object
, userdata
->logon_divs
), error
);
481 SET_OR_FAIL(gums_set_user_hours(*object
, userdata
->hours_len
, userdata
->hours
), error
);
483 SET_OR_FAIL(gums_set_user_unknown_3(*object
, userdata
->unknown_3
), error
);
484 SET_OR_FAIL(gums_set_user_unknown_5(*object
, userdata
->unknown_5
), error
);
485 SET_OR_FAIL(gums_set_user_unknown_6(*object
, userdata
->unknown_6
), error
);
487 SET_OR_FAIL(gums_set_user_logon_time(*object
, *(userdata
->logon_time
)), error
);
488 SET_OR_FAIL(gums_set_user_logoff_time(*object
, *(userdata
->logoff_time
)), error
);
489 SET_OR_FAIL(gums_set_user_kickoff_time(*object
, *(userdata
->kickoff_time
)), error
);
490 SET_OR_FAIL(gums_set_user_pass_last_set_time(*object
, *(userdata
->pass_last_set_time
)), error
);
491 SET_OR_FAIL(gums_set_user_pass_can_change_time(*object
, *(userdata
->pass_can_change_time
)), error
);
492 SET_OR_FAIL(gums_set_user_pass_must_change_time(*object
, *(userdata
->pass_must_change_time
)), error
);
494 pwd
= data_blob(userdata
->nt_pw_ptr
, NT_HASH_LEN
);
495 ret
= gums_set_user_nt_pwd(*object
, pwd
);
496 data_blob_clear_free(&pwd
);
497 if (!NT_STATUS_IS_OK(ret
)) {
498 DEBUG(5, ("user_data_to_gums_object: failed to set nt password!\n"));
501 pwd
= data_blob(userdata
->lm_pw_ptr
, LM_HASH_LEN
);
502 ret
= gums_set_user_lm_pwd(*object
, pwd
);
503 data_blob_clear_free(&pwd
);
504 if (!NT_STATUS_IS_OK(ret
)) {
505 DEBUG(5, ("user_data_to_gums_object: failed to set lanman password!\n"));
513 talloc_destroy((*object
)->mem_ctx
);
518 static NTSTATUS
group_data_to_gums_object(GUMS_OBJECT
**object
, struct tdbsam2_group_data
*groupdata
)
520 NTSTATUS ret
= NT_STATUS_UNSUCCESSFUL
;
522 if (!object
|| !groupdata
) {
523 DEBUG(0, ("tdbsam2_group_data_to_gums_object: no NULL pointers are accepted here!\n"));
527 /* groupdata->xcounter */
528 /* groupdata->sec_desc */
530 SET_OR_FAIL(gums_set_object_sid(*object
, groupdata
->group_sid
), error
);
531 SET_OR_FAIL(gums_set_object_name(*object
, groupdata
->name
), error
);
533 if (groupdata
->description
)
534 SET_OR_FAIL(gums_set_object_description(*object
, groupdata
->description
), error
);
536 if (groupdata
->count
)
537 SET_OR_FAIL(gums_set_group_members(*object
, groupdata
->count
, groupdata
->members
), error
);
543 talloc_destroy((*object
)->mem_ctx
);
548 static NTSTATUS
domain_data_to_gums_object(GUMS_OBJECT
**object
, struct tdbsam2_domain_data
*domdata
)
551 NTSTATUS ret
= NT_STATUS_UNSUCCESSFUL
;
553 if (!object
|| !*object
|| !domdata
) {
554 DEBUG(0, ("tdbsam2_domain_data_to_gums_object: no NULL pointers are accepted here!\n"));
555 return NT_STATUS_INVALID_PARAMETER
;
558 /* domdata->xcounter */
559 /* domdata->sec_desc */
561 SET_OR_FAIL(gums_set_object_sid(*object
, domdata
->dom_sid
), error
);
562 SET_OR_FAIL(gums_set_object_name(*object
, domdata
->name
), error
);
564 if (domdata
->description
)
565 SET_OR_FAIL(gums_set_object_description(*object
, domdata
->description
), error
);
571 talloc_destroy((*object
)->mem_ctx
);
576 static NTSTATUS
priv_data_to_gums_object(GUMS_OBJECT
**object
, struct tdbsam2_priv_data
*privdata
)
579 NTSTATUS ret
= NT_STATUS_UNSUCCESSFUL
;
581 if (!object
|| !*object
|| !privdata
) {
582 DEBUG(0, ("tdbsam2_priv_data_to_gums_object: no NULL pointers are accepted here!\n"));
586 /* domdata->xcounter */
587 /* domdata->sec_desc */
589 SET_OR_FAIL(gums_set_priv_luid_attr(*object
, privdata
->privilege
), error
);
590 SET_OR_FAIL(gums_set_object_name(*object
, privdata
->name
), error
);
592 if (privdata
->description
)
593 SET_OR_FAIL(gums_set_object_description(*object
, privdata
->description
), error
);
596 SET_OR_FAIL(gums_set_priv_members(*object
, privdata
->count
, privdata
->members
), error
);
602 talloc_destroy((*object
)->mem_ctx
);
607 static NTSTATUS
data_to_gums_object(GUMS_OBJECT
**object
, struct tdbsam2_object
*data
)
612 if (!object
|| !data
) {
613 DEBUG(0, ("tdbsam2_user_data_to_gums_object: no NULL structure pointers are accepted here!\n"));
614 ret
= NT_STATUS_INVALID_PARAMETER
;
618 ret
= gums_create_object(object
, data
->type
);
619 if (!NT_STATUS_IS_OK(ret
)) {
620 DEBUG(5, ("tdbsam2_user_data_to_gums_object: error creating gums object!\n"));
624 switch (data
->type
) {
626 case GUMS_OBJ_DOMAIN
:
627 ret
= domain_data_to_gums_object(object
, data
->data
.domain
);
630 case GUMS_OBJ_NORMAL_USER
:
631 ret
= user_data_to_gums_object(object
, data
->data
.user
);
636 ret
= group_data_to_gums_object(object
, data
->data
.group
);
639 case GUMS_OBJ_PRIVILEGE
:
640 ret
= priv_data_to_gums_object(object
, data
->data
.priv
);
644 ret
= NT_STATUS_UNSUCCESSFUL
;
652 /* GUMM object functions */
654 static NTSTATUS
tdbsam2_get_domain_sid(DOM_SID
*sid
, const char* name
)
663 return NT_STATUS_INVALID_PARAMETER
;
665 if (!NT_STATUS_IS_OK(ret
= opentdb(&tdb
, True
))) {
669 /* Data is stored in all lower-case */
670 fstrcpy(domname
, name
);
673 if (!NT_STATUS_IS_OK(ret
= get_object_by_name(tdb
, &go
, domname
))) {
675 DEBUG(0, ("tdbsam2_get_domain_sid: Error fetching database!\n"));
679 if (gums_get_object_type(go
) != GUMS_OBJ_DOMAIN
) {
680 DEBUG(5, ("tdbsam2_get_domain_sid: Requested object is not a domain!\n"));
681 ret
= NT_STATUS_OBJECT_TYPE_MISMATCH
;
685 sid_copy(sid
, gums_get_object_sid(go
));
691 gums_destroy_object(&go
);
696 static NTSTATUS
get_next_sid(TDB_CONTEXT
*tdb
, DOM_SID
*sid
)
701 TDB_DATA dom_sid_key
;
705 /* Find the domain SID */
706 if (!NT_STATUS_IS_OK(tdbsam2_get_domain_sid(&dom_sid
, global_myname()))) {
707 DEBUG(0, ("get_next_sid: cannot found the domain sid!!\n"));
708 return NT_STATUS_UNSUCCESSFUL
;
711 /* Lock the domain record */
712 sid_to_string(dom_sid_str
, &dom_sid
);
713 dom_sid_key
.dptr
= dom_sid_str
;
714 dom_sid_key
.dsize
= strlen(dom_sid_key
.dptr
) + 1;
716 if(tdb_chainlock(tdb
, dom_sid_key
) != 0) {
717 DEBUG(0, ("get_next_sid: unable to lock domain record!\n"));
718 return NT_STATUS_UNSUCCESSFUL
;
721 /* Get the domain object */
722 ret
= get_object_by_sid(tdb
, &go
, &dom_sid
);
723 if (!NT_STATUS_IS_OK(ret
)) {
724 DEBUG(0, ("get_next_sid: unable to get root Domain object!\n"));
725 ret
= NT_STATUS_INTERNAL_DB_ERROR
;
729 new_rid
= gums_get_domain_next_rid(go
);
731 /* Increment the RID Counter */
732 gums_set_domain_next_rid(go
, new_rid
+1);
734 /* Store back Domain object */
735 ret
= store_object(tdb
, go
, TDB_MODIFY
);
736 if (!NT_STATUS_IS_OK(ret
)) {
737 DEBUG(0, ("get_next_sid: unable to update root Domain object!\n"));
738 ret
= NT_STATUS_INTERNAL_DB_ERROR
;
742 /* Build the Domain SID to return */
743 sid_copy(sid
, &dom_sid
);
745 if (!sid_append_rid(sid
, new_rid
)) {
746 DEBUG(0, ("get_next_sid: unable to build new SID !?!\n"));
747 ret
= NT_STATUS_UNSUCCESSFUL
;
754 /* Unlock the Domain object */
755 tdb_chainunlock(tdb
, dom_sid_key
);
761 NTSTATUS (*get_sequence_number
) (void);
764 extern DOM_SID global_sid_NULL
;
766 static NTSTATUS
tdbsam2_new_object(DOM_SID
*sid
, const char *name
, const int obj_type
)
769 NTSTATUS ret
= NT_STATUS_OK
;
774 const char *defpw
= "NOPASSWORDXXXXXX";
775 uint8 defhours
[21] = {255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255};
778 DEBUG(0, ("tdbsam2_new_object: no NULL pointers are accepted here!\n"));
779 return NT_STATUS_INVALID_PARAMETER
;
782 if (!NT_STATUS_IS_OK(ret
= opentdb(&tdb
, False
))) {
786 if (!NT_STATUS_IS_OK(ret
= gums_create_object(&go
, obj_type
))) {
791 if (obj_type
!= GUMS_OBJ_PRIVILEGE
) {
793 ret
= NT_STATUS_INVALID_PARAMETER
;
797 if (obj_type
== GUMS_OBJ_DOMAIN
) {
798 sid_copy(sid
, get_global_sam_sid());
800 if (!NT_STATUS_IS_OK(ret
= get_next_sid(tdb
, sid
)))
804 gums_set_object_sid(go
, sid
);
807 gums_set_object_name(go
, name
);
808 gums_set_object_seq_num(go
, 1);
810 /*obj.data.domain->sec_desc*/
813 case GUMS_OBJ_NORMAL_USER
:
815 init_nt_time(&null_time
);
817 gums_set_user_logon_time(go
, null_time
);
818 gums_set_user_logoff_time(go
, null_time
);
819 gums_set_user_kickoff_time(go
, null_time
);
820 gums_set_user_pass_last_set_time(go
, null_time
);
821 gums_set_user_pass_can_change_time(go
, null_time
);
822 gums_set_user_pass_must_change_time(go
, null_time
);
824 pw
= data_blob(defpw
, NT_HASH_LEN
);
825 gums_set_user_nt_pwd(go
, pw
);
826 gums_set_user_lm_pwd(go
, pw
);
829 gums_set_user_logon_divs(go
, 168);
830 gums_set_user_hours(go
, 21, defhours
);
832 gums_set_user_unknown_3(go
, 0x00ffffff);
833 gums_set_user_bad_password_count(go
, 0);
834 gums_set_user_logon_count(go
, 0);
835 gums_set_user_unknown_6(go
, 0x000004ec);
843 case GUMS_OBJ_DOMAIN
:
845 gums_set_domain_next_rid(go
, 0x3e9);
849 case GUMS_OBJ_PRIVILEGE
:
854 ret
= NT_STATUS_OBJECT_TYPE_MISMATCH
;
858 ret
= store_object(tdb
, go
, TDB_INSERT
);
862 gums_destroy_object(&go
);
867 static NTSTATUS
tdbsam2_delete_object(const DOM_SID
*sid
)
869 /* TODO: need to address privilege deletion */
870 NTSTATUS ret
= NT_STATUS_OK
;
877 DEBUG(0, ("tdbsam2_delete_object: no NULL pointers are accepted here!\n"));
878 return NT_STATUS_INVALID_PARAMETER
;
881 if (!NT_STATUS_IS_OK(ret
= opentdb(&tdb
, False
))) {
885 slprintf(keystr
, sizeof(keystr
)-1, "%s%s", SIDPREFIX
, sid_string_static(sid
));
887 key
.dsize
= strlen(keystr
) + 1;
889 data
= tdb_fetch(tdb
, key
);
891 DEBUG(5, ("tdbsam2_delete_object: Error fetching database, SID entry not found!\n"));
892 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdb
)));
893 DEBUGADD(5, (" Key: %s\n", keystr
));
894 ret
= NT_STATUS_UNSUCCESSFUL
;
898 if (tdb_delete(tdb
, key
) != TDB_SUCCESS
) {
899 DEBUG(5, ("tdbsam2_delete_object: Error deleting object!\n"));
900 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdb
)));
901 DEBUGADD(5, (" Key: %s\n", keystr
));
902 ret
= NT_STATUS_UNSUCCESSFUL
;
906 if (!NT_STATUS_IS_OK(init_object_from_buffer(&go
, data
.dptr
, data
.dsize
))) {
907 DEBUG(0, ("tdbsam2_delete_object: Error fetching database, malformed entry!\n"));
908 ret
= NT_STATUS_UNSUCCESSFUL
;
913 case GUMS_OBJ_DOMAIN
:
914 /* FIXME: SHOULD WE ALLOW TO DELETE DOMAINS ? */
917 case GUMS_OBJ_NORMAL_USER
:
918 slprintf(keystr
, sizeof(keystr
) - 1, "%s%s", NAMEPREFIX
, gums_get_object_name(go
));
921 ret
= NT_STATUS_OBJECT_TYPE_MISMATCH
;
926 key
.dsize
= strlen(keystr
) + 1;
928 if (tdb_delete(tdb
, key
) != TDB_SUCCESS
) {
929 DEBUG(5, ("tdbsam2_delete_object: Error deleting object!\n"));
930 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdb
)));
931 DEBUGADD(5, (" Key: %s\n", keystr
));
932 ret
= NT_STATUS_UNSUCCESSFUL
;
936 /* TODO: update the general database counter */
939 gums_destroy_object(&go
);
940 SAFE_FREE(data
.dptr
);
944 static NTSTATUS
tdbsam2_get_object_from_sid(GUMS_OBJECT
**object
, const DOM_SID
*sid
, const int obj_type
)
949 if (!object
|| !sid
) {
950 DEBUG(0, ("tdbsam2_get_object_from_sid: no NULL pointers are accepted here!\n"));
951 return NT_STATUS_INVALID_PARAMETER
;
954 if (!NT_STATUS_IS_OK(ret
= opentdb(&tdb
, True
))) {
958 ret
= get_object_by_sid(tdb
, object
, sid
);
959 if (!NT_STATUS_IS_OK(ret
) || (obj_type
&& gums_get_object_type(*object
) != obj_type
)) {
960 DEBUG(0, ("tdbsam2_get_object_from_sid: %s\n", nt_errstr(ret
)));
968 gums_destroy_object(object
);
973 static NTSTATUS
tdbsam2_get_object_from_name(GUMS_OBJECT
**object
, const char *name
, const int obj_type
)
978 if (!object
|| !name
) {
979 DEBUG(0, ("tdbsam2_get_object_from_name: no NULL pointers are accepted here!\n"));
980 return NT_STATUS_INVALID_PARAMETER
;
983 if (!NT_STATUS_IS_OK(ret
= opentdb(&tdb
, True
))) {
988 ret
= get_object_by_name(tdb
, object
, name
);
989 if (!NT_STATUS_IS_OK(ret
) || (obj_type
&& gums_get_object_type(*object
) != obj_type
)) {
990 DEBUG(0, ("tdbsam2_get_object_from_name: %s\n", nt_errstr(ret
)));
998 gums_destroy_object(object
);
1003 /* This function is used to get the list of all objects changed since base_time, it is
1004 used to support PDC<->BDC synchronization */
1005 NTSTATUS (*get_updated_objects
) (GUMS_OBJECT
**objects
, const NTTIME base_time
);
1007 static NTSTATUS
tdbsam2_enumerate_objects_start(void **handle
, const DOM_SID
*sid
, const int obj_type
)
1009 struct tdbsam2_enum_objs
*teo
, *t
;
1011 teo
= (struct tdbsam2_enum_objs
*)malloc(sizeof(struct tdbsam2_enum_objs
));
1013 DEBUG(0, ("tdbsam2_enumerate_objects_start: Out of Memory!\n"));
1014 return NT_STATUS_NO_MEMORY
;
1016 memset(teo
, 0, sizeof(struct tdbsam2_enum_objs
));
1018 teo
->type
= obj_type
;
1020 teo
->dom_sid
= (DOM_SID
*)malloc(sizeof(DOM_SID
));
1021 if (!teo
->dom_sid
) {
1022 DEBUG(0, ("tdbsam2_enumerate_objects_start: Out of Memory!\n"));
1023 return NT_STATUS_NO_MEMORY
;
1025 sid_copy(teo
->dom_sid
, sid
);
1028 if (!NT_STATUS_IS_OK(opentdb(&(teo
->db
), True
)))
1030 DEBUG(0, ("tdbsam2_enumerate_objects_start: Unable to open database (%s)!\n", ts2_privs
->storage
));
1032 return NT_STATUS_UNSUCCESSFUL
;
1035 if (!ts2_privs
->teo_handlers
) {
1036 ts2_privs
->teo_handlers
= teo
;
1038 t
= ts2_privs
->teo_handlers
;
1047 teo
->key
= tdb_firstkey(teo
->db
);
1049 return NT_STATUS_OK
;
1052 static NTSTATUS
tdbsam2_enumerate_objects_get_next(GUMS_OBJECT
**object
, void *handle
)
1056 struct tdbsam2_enum_objs
*teo
;
1057 const char *prefix
= SIDPREFIX
;
1058 const int preflen
= strlen(prefix
);
1059 fstring dom_sid_str
;
1060 int dom_sid_str_len
= 0;
1062 if (!object
|| !handle
) {
1063 DEBUG(0, ("tdbsam2_get_object_from_sid: no NULL pointers are accepted here!\n"));
1064 return NT_STATUS_INVALID_PARAMETER
;
1067 teo
= (struct tdbsam2_enum_objs
*)handle
;
1070 sid_to_string(dom_sid_str
, teo
->dom_sid
);
1071 dom_sid_str_len
= strlen(dom_sid_str
);
1074 while ((teo
->key
.dptr
!= NULL
)) {
1075 int len
, version
, type
, size
;
1078 if (strncmp(teo
->key
.dptr
, prefix
, preflen
)) {
1079 teo
->key
= tdb_nextkey(teo
->db
, teo
->key
);
1083 if (dom_sid_str_len
!= 0) {
1084 if (strncmp(&(teo
->key
.dptr
[preflen
]), dom_sid_str
, dom_sid_str_len
)) {
1085 teo
->key
= tdb_nextkey(teo
->db
, teo
->key
);
1090 data
= tdb_fetch(teo
->db
, teo
->key
);
1092 DEBUG(5, ("tdbsam2_enumerate_objects_get_next: Error fetching database, SID entry not found!\n"));
1093 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(teo
->db
)));
1094 DEBUGADD(5, (" Key: %s\n", teo
->key
.dptr
));
1095 ret
= NT_STATUS_UNSUCCESSFUL
;
1099 len
= tdb_unpack (data
.dptr
, data
.dsize
, TDB_FORMAT_STRING
,
1105 DEBUG(5, ("tdbsam2_enumerate_objects_get_next: Error unable to unpack data!\n"));
1106 ret
= NT_STATUS_UNSUCCESSFUL
;
1111 if (teo
->type
&& type
!= teo
->type
) {
1112 SAFE_FREE(data
.dptr
);
1114 teo
->key
= tdb_nextkey(teo
->db
, teo
->key
);
1121 if (teo
->key
.dptr
== NULL
) { /* no more objs */
1122 ret
= NT_STATUS_NO_MORE_ENTRIES
;
1126 if (!NT_STATUS_IS_OK(ret
= init_object_from_buffer(object
, data
.dptr
, data
.dsize
))) {
1127 SAFE_FREE(data
.dptr
);
1128 DEBUG(0, ("tdbsam2_enumerate_objects_get_next: Error fetching database, malformed entry!\n"));
1129 ret
= NT_STATUS_UNSUCCESSFUL
;
1132 SAFE_FREE(data
.dptr
);
1134 /* prepare next run */
1135 teo
->key
= tdb_nextkey(teo
->db
, teo
->key
);
1141 static NTSTATUS
tdbsam2_enumerate_objects_stop(void *handle
)
1143 struct tdbsam2_enum_objs
*teo
, *t
, *p
;
1145 teo
= (struct tdbsam2_enum_objs
*)handle
;
1147 if (ts2_privs
->teo_handlers
== teo
) {
1148 ts2_privs
->teo_handlers
= teo
->next
;
1150 t
= ts2_privs
->teo_handlers
;
1155 DEBUG(0, ("tdbsam2_enumerate_objects_stop: Error, handle not found!\n"));
1156 return NT_STATUS_UNSUCCESSFUL
;
1163 SAFE_FREE(teo
->dom_sid
);
1166 return NT_STATUS_OK
;
1169 static NTSTATUS
tdbsam2_set_object(const GUMS_OBJECT
*go
)
1175 return NT_STATUS_INVALID_PARAMETER
;
1177 if (!NT_STATUS_IS_OK(ret
= opentdb(&tdb
, False
))) {
1181 ret
= store_object(tdb
, go
, TDB_REPLACE
);
1188 /* set object values function */
1189 static NTSTATUS (*set_object_values
) (DOM_SID
*sid
, uint32 count
, GUMS_DATA_SET
*data_set
);
1191 /* Group related functions */
1192 static NTSTATUS (*add_memberss_to_group
) (const DOM_SID
*group
, const DOM_SID
**members
);
1193 NTSTATUS (*delete_members_from_group
) (const DOM_SID
*group
, const DOM_SID
**members
);
1194 static NTSTATUS (*enumerate_group_members
) (DOM_SID
**members
, const DOM_SID
*sid
, const int type
);
1196 static NTSTATUS (*get_sid_groups
) (DOM_SID
**groups
, const DOM_SID
*sid
);
1198 static NTSTATUS (*lock_sid
) (const DOM_SID
*sid
);
1199 static NTSTATUS (*unlock_sid
) (const DOM_SID
*sid
);
1201 /* privileges related functions */
1203 static NTSTATUS (*add_members_to_privilege
) (const LUID_ATTR
*priv
, const DOM_SID
**members
);
1204 static NTSTATUS (*delete_members_from_privilege
) (const LUID_ATTR
*priv
, const DOM_SID
**members
);
1205 static NTSTATUS (*enumerate_privilege_members
) (DOM_SID
**members
, const LUID_ATTR
*priv
);
1206 static NTSTATUS (*get_sid_privileges
) (DOM_SID
**privs
, const DOM_SID
*sid
);
1207 /* warning!: set_privilege will overwrite a prior existing privilege if such exist */
1208 static NTSTATUS (*set_privilege
) (GUMS_PRIVILEGE
*priv
);
1211 static void free_tdbsam2_private_data(void **vp
)
1213 struct tdbsam2_private_data
**tdb_privs
= (struct tdbsam2_private_data
**)vp
;
1214 while (ts2_privs
->teo_handlers
)
1215 tdbsam2_enumerate_objects_stop(ts2_privs
->teo_handlers
);
1217 /* No need to free any further, as it is talloc()ed */
1220 static NTSTATUS
init_tdbsam2(GUMS_FUNCTIONS
*fns
, const char *storage
)
1226 fns
->name
= talloc_strdup(fns
->mem_ctx
, "tdbsam2");
1228 fns
->get_domain_sid
= tdbsam2_get_domain_sid
;
1229 /* fns->get_sequence_number = tdbsam2_get_sequence_number; */
1230 fns
->new_object
= tdbsam2_new_object
;
1231 fns
->delete_object
= tdbsam2_delete_object
;
1232 fns
->get_object_from_sid
= tdbsam2_get_object_from_sid
;
1233 fns
->get_object_from_name
= tdbsam2_get_object_from_name
;
1234 /* fns->get_updated_objects = tdbsam2_get_updated_objects; */
1235 fns
->enumerate_objects_start
= tdbsam2_enumerate_objects_start
;
1236 fns
->enumerate_objects_get_next
= tdbsam2_enumerate_objects_get_next
;
1237 fns
->enumerate_objects_stop
= tdbsam2_enumerate_objects_stop
;
1238 fns
->set_object
= tdbsam2_set_object
;
1239 /* fns->set_object_values = tdbsam2_set_object_values;
1240 fns->add_members_to_group = tdbsam2_add_members_to_group;
1241 fns->delete_members_from_group = tdbsam2_delete_members_from_group;
1242 fns->enumerate_group_members = tdbsam2_enumerate_group_members;
1243 fns->get_sid_groups = tdbsam2_get_sid_groups;
1244 fns->lock_sid = tdbsam2_lock_sid;
1245 fns->unlock_sid = tdbsam2_unlock_sid;
1246 fns->add_members_to_privilege = tdbsam2_add_members_to_privilege;
1247 fns->delete_members_from_privilege = tdbsam2_delete_members_from_privilege;
1248 fns->enumerate_privilege_members = tdbsam2_enumerate_privilege_members;
1249 fns->get_sid_privileges = tdbsam2_get_sid_privileges;
1250 fns->set_privilege = tdbsam2_set_privilege; */
1252 ts2_privs
= talloc_zero(fns
->mem_ctx
, sizeof(struct tdbsam2_private_data
));
1254 DEBUG(0, ("talloc() failed for tdbsam2 private_data!\n"));
1255 return NT_STATUS_NO_MEMORY
;
1259 ts2_privs
->storage
= talloc_strdup(fns
->mem_ctx
, storage
);
1262 get_private_directory(tdbfile
);
1263 pstrcat(tdbfile
, "/");
1264 pstrcat(tdbfile
, TDB_FILE_NAME
);
1265 ts2_privs
->storage
= talloc_strdup(fns
->mem_ctx
, tdbfile
);
1268 /* check tdb exist (or create it) */
1270 /* Find the domain SID */
1271 if (!NT_STATUS_IS_OK(tdbsam2_get_domain_sid(&dom_sid
, global_myname()))) {
1272 /* db file does not exist or it is not inited */
1273 /* make the tdb file */
1274 if (!NT_STATUS_IS_OK(ret
= opentdb(&tdb
, False
))) {
1279 if (!NT_STATUS_IS_OK(tdbsam2_get_domain_sid(&dom_sid
, "BUILTIN"))) {
1280 gums_init_builtin_domain();
1283 gums_init_domain(get_global_sam_sid(), global_myname());
1286 fns
->private_data
= &ts2_privs
;
1287 fns
->free_private_data
= free_tdbsam2_private_data
;
1289 return NT_STATUS_OK
;
1292 NTSTATUS
gums_tdbsam2_init(void)
1295 if ((gums_tdbsam2_debug_class = debug_add_class("gums_tdbsam2")) == -1) {
1296 DEBUG(0, ("gums_tdbsam2: unable to register my own debug class! going on ...\n"));
1297 gums_tdbsam2_debug_class = DBGC_ALL;
1300 return gums_register_module(GUMS_INTERFACE_VERSION
, "tdbsam2", init_tdbsam2
);