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"
25 static int gums_tdbsam2_debug_class
= DBGC_ALL
;
28 #define DBGC_CLASS gums_tdbsam2_debug_class
31 #define TDBSAM_VERSION 20021215
32 #define TDB_FILE_NAME "tdbsam2.tdb"
33 #define NAMEPREFIX "NAME_"
34 #define SIDPREFIX "SID_"
35 #define PRIVILEGEPREFIX "PRIV_"
37 #define TDB_FORMAT_STRING "ddB"
39 #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)
40 #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)
44 struct tdbsam2_enum_objs
{
49 struct tdbsam2_enum_objs
*next
;
53 struct tdbsam2_domain_data
*domain
;
54 struct tdbsam2_user_data
*user
;
55 struct tdbsam2_group_data
*group
;
56 struct tdbsam2_priv_data
*priv
;
59 struct tdbsam2_object
{
62 union tdbsam2_data data
;
65 struct tdbsam2_private_data
{
68 struct tdbsam2_enum_objs
*teo_handlers
;
71 static struct tdbsam2_private_data
*ts2_privs
;
74 static NTSTATUS
init_object_from_buffer(GUMS_OBJECT
**go
, char *buffer
, int size
)
77 NTSTATUS ret
= NT_STATUS_UNSUCCESSFUL
;
80 char *obj_data
= NULL
;
85 mem_ctx
= talloc_init("init_object_from_buffer");
87 DEBUG(0, ("init_object_from_buffer: Out of memory!\n"));
88 return NT_STATUS_NO_MEMORY
;
91 len
= tdb_unpack (buffer
, size
, TDB_FORMAT_STRING
,
94 &data_size
, &obj_data
);
96 if (len
== -1 || data_size
<= 0)
99 /* version is checked inside this function so that backward compatibility code can be
101 this way we can easily handle database format upgrades */
102 if (version
!= TDBSAM_VERSION
) {
103 DEBUG(3,("init_tdbsam2_object_from_buffer: Error, db object has wrong tdbsam version!\n"));
107 /* be sure the string is terminated before trying to parse it */
108 if (obj_data
[data_size
- 1] != '\0')
109 obj_data
[data_size
- 1] = '\0';
111 *go
= (GUMS_OBJECT
*)talloc_zero(mem_ctx
, sizeof(GUMS_OBJECT
));
112 TALLOC_CHECK(*go
, ret
, done
);
116 case GUMS_OBJ_DOMAIN
:
117 iret
= gen_parse(mem_ctx
, pinfo_tdbsam2_domain_data
, (char *)(*go
), obj_data
);
122 iret
= gen_parse(mem_ctx
, pinfo_tdbsam2_group_data
, (char *)(*go
), obj_data
);
125 case GUMS_OBJ_NORMAL_USER
:
126 iret
= gen_parse(mem_ctx
, pinfo_tdbsam2_user_data
, (char *)(*go
), obj_data
);
129 case GUMS_OBJ_PRIVILEGE
:
130 iret
= gen_parse(mem_ctx
, pinfo_tdbsam2_priv_data
, (char *)(*go
), obj_data
);
134 DEBUG(3,("init_object_from_buffer: Error, wrong object type number!\n"));
139 DEBUG(0, ("init_object_from_buffer: Fatal Error! Unable to parse object!\n"));
140 DEBUG(0, ("init_object_from_buffer: DB Corrupt ?"));
144 (*go
)->mem_ctx
= mem_ctx
;
152 static NTSTATUS
init_buffer_from_object(char **buffer
, size_t *len
, TALLOC_CTX
*mem_ctx
, GUMS_OBJECT
*object
)
160 return NT_STATUS_INVALID_PARAMETER
;
162 switch (gums_get_object_type(object
)) {
164 case GUMS_OBJ_DOMAIN
:
165 genbuf
= gen_dump(mem_ctx
, pinfo_tdbsam2_domain_data
, (char *)object
, 0);
170 genbuf
= gen_dump(mem_ctx
, pinfo_tdbsam2_group_data
, (char *)object
, 0);
173 case GUMS_OBJ_NORMAL_USER
:
174 genbuf
= gen_dump(mem_ctx
, pinfo_tdbsam2_user_data
, (char *)object
, 0);
177 case GUMS_OBJ_PRIVILEGE
:
178 genbuf
= gen_dump(mem_ctx
, pinfo_tdbsam2_priv_data
, (char *)object
, 0);
182 DEBUG(3,("init_buffer_from_object: Error, wrong object type number!\n"));
183 return NT_STATUS_UNSUCCESSFUL
;
186 if (genbuf
== NULL
) {
187 DEBUG(0, ("init_buffer_from_object: Fatal Error! Unable to dump object!\n"));
188 return NT_STATUS_UNSUCCESSFUL
;
191 buflen
= tdb_pack(NULL
, 0, TDB_FORMAT_STRING
,
194 strlen(genbuf
) + 1, genbuf
);
196 *buffer
= talloc(mem_ctx
, buflen
);
197 TALLOC_CHECK(*buffer
, ret
, done
);
199 *len
= tdb_pack(*buffer
, buflen
, TDB_FORMAT_STRING
,
202 strlen(genbuf
) + 1, genbuf
);
204 if (*len
!= buflen
) {
205 DEBUG(0, ("init_buffer_from_object: something odd is going on here: bufflen (%d) != len (%d) in tdb_pack operations!\n",
208 ret
= NT_STATUS_UNSUCCESSFUL
;
217 static NTSTATUS
opentdb(TDB_CONTEXT
**tdb
, BOOL readonly
)
220 return NT_STATUS_INVALID_PARAMETER
;
222 *tdb
= tdb_open_log(ts2_privs
->storage
, 0, TDB_DEFAULT
, readonly
?(O_RDONLY
):(O_RDWR
| O_CREAT
), 0600);
225 DEBUG(0, ("opentdb: Unable to open database (%s)!\n", ts2_privs
->storage
));
226 return NT_STATUS_UNSUCCESSFUL
;
232 static NTSTATUS
get_object_by_sid(TDB_CONTEXT
*tdb
, GUMS_OBJECT
**obj
, const DOM_SID
*sid
)
239 return NT_STATUS_INVALID_PARAMETER
;
241 slprintf(keystr
, sizeof(keystr
)-1, "%s%s", SIDPREFIX
, sid_string_static(sid
));
243 key
.dsize
= strlen(keystr
) + 1;
245 data
= tdb_fetch(tdb
, key
);
247 DEBUG(5, ("get_object_by_sid: Entry not found!\n"));
248 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdb
)));
249 DEBUGADD(5, (" Key: %s\n", keystr
));
250 ret
= NT_STATUS_NOT_FOUND
;
254 if (!NT_STATUS_IS_OK(init_object_from_buffer(obj
, data
.dptr
, data
.dsize
))) {
255 DEBUG(0, ("get_object_by_sid: Error fetching database, malformed entry!\n"));
256 ret
= NT_STATUS_UNSUCCESSFUL
;
263 SAFE_FREE(data
.dptr
);
267 static NTSTATUS
get_object_by_name(TDB_CONTEXT
*tdb
, GUMS_OBJECT
**obj
, const char* name
)
270 NTSTATUS ret
= NT_STATUS_OK
;
279 return NT_STATUS_INVALID_PARAMETER
;
281 /* Data is stored in all lower-case */
282 fstrcpy(objname
, name
);
285 slprintf(keystr
, sizeof(keystr
)-1, "%s%s", NAMEPREFIX
, objname
);
287 key
.dsize
= strlen(keystr
) + 1;
289 data
= tdb_fetch(tdb
, key
);
291 DEBUG(5, ("get_object_by_name: Entry not found!\n"));
292 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdb
)));
293 DEBUGADD(5, (" Key: %s\n", keystr
));
294 ret
= NT_STATUS_NOT_FOUND
;
298 fstrcpy(sidstr
, data
.dptr
);
299 sidstr_len
= data
.dsize
;
301 SAFE_FREE(data
.dptr
);
303 if (sidstr_len
<= 0) {
304 DEBUG(5, ("get_object_by_name: Error unpacking database object!\n"));
305 ret
= NT_STATUS_UNSUCCESSFUL
;
309 if (!string_to_sid(&sid
, sidstr
)) {
310 DEBUG(5, ("get_object_by_name: Error invalid sid string found in database object!\n"));
311 ret
= NT_STATUS_UNSUCCESSFUL
;
316 if (NT_STATUS_IS_OK(ret
))
317 return get_object_by_sid(tdb
, obj
, &sid
);
321 /* store a tdbsam2_object
322 * flag: TDB_REPLACE or TDB_MODIFY or TDB_INSERT
325 static NTSTATUS
store_object(TDB_CONTEXT
*tdb
, const GUMS_OBJECT
*object
, int flag
)
328 NTSTATUS ret
= NT_STATUS_OK
;
329 TDB_DATA data
, data2
, key
, key2
;
337 /* TODO: on object renaming/replacing this function should
338 * check name->sid record and delete the old one
341 mem_ctx
= talloc_init("store_object");
343 DEBUG(0, ("store_object: Out of memory!\n"));
344 return NT_STATUS_NO_MEMORY
;
347 if (!NT_STATUS_IS_OK(ret
= init_buffer_from_object(&(data
.dptr
), &(data
.dsize
), mem_ctx
, object
)))
350 switch (object
->type
) {
352 case GUMS_OBJ_DOMAIN
:
355 case GUMS_OBJ_NORMAL_USER
:
357 fstrcpy(sidstr
, sid_string_static(gums_get_object_sid(object
)));
358 slprintf(keystr
, sizeof(keystr
) - 1, "%s%s", SIDPREFIX
, sidstr
);
362 ret
= NT_STATUS_UNSUCCESSFUL
;
366 /* Data is stored in all lower-case */
367 fstrcpy(objname
, gums_get_object_name(object
));
370 slprintf(namestr
, sizeof(namestr
) - 1, "%s%s", NAMEPREFIX
, objname
);
372 if (object
->type
!= GUMS_OBJ_PRIVILEGE
) {
374 key
.dsize
= strlen(keystr
) + 1;
376 if ((r
= tdb_store(tdb
, key
, data
, flag
)) != TDB_SUCCESS
) {
377 DEBUG(0, ("store_object: Unable to modify TDBSAM!\n"));
378 DEBUGADD(0, (" Error: %s", tdb_errorstr(tdb
)));
379 DEBUGADD(0, (" occured while storing sid record (%s)\n", keystr
));
380 if (r
== TDB_ERR_EXISTS
)
381 ret
= NT_STATUS_UNSUCCESSFUL
;
383 ret
= NT_STATUS_INTERNAL_DB_ERROR
;
388 data2
.dsize
= strlen(sidstr
) + 1;
390 key2
.dsize
= strlen(namestr
) + 1;
392 if ((r
= tdb_store(tdb
, key2
, data2
, flag
)) != TDB_SUCCESS
) {
393 DEBUG(0, ("store_object: Unable to modify TDBSAM!\n"));
394 DEBUGADD(0, (" Error: %s", tdb_errorstr(tdb
)));
395 DEBUGADD(0, (" occured while storing name record (%s)\n", keystr
));
396 DEBUGADD(0, (" attempting rollback operation.\n"));
397 if ((tdb_delete(tdb
, key
)) != TDB_SUCCESS
) {
398 DEBUG(0, ("store_object: Unable to rollback! Check database consitency!\n"));
400 if (r
== TDB_ERR_EXISTS
)
401 ret
= NT_STATUS_UNSUCCESSFUL
;
403 ret
= NT_STATUS_INTERNAL_DB_ERROR
;
408 key
.dsize
= strlen(keystr
) + 1;
410 if ((r
= tdb_store(tdb
, key
, data
, flag
)) != TDB_SUCCESS
) {
411 DEBUG(0, ("store_object: Unable to modify TDBSAM!\n"));
412 DEBUGADD(0, (" Error: %s", tdb_errorstr(tdb
)));
413 DEBUGADD(0, (" occured while storing sid record (%s)\n", keystr
));
414 if (r
== TDB_ERR_EXISTS
)
415 ret
= NT_STATUS_UNSUCCESSFUL
;
417 ret
= NT_STATUS_INTERNAL_DB_ERROR
;
422 /* TODO: update the general database counter */
423 /* TODO: update this entry counter too */
426 talloc_destroy(mem_ctx
);
431 static NTSTATUS
user_data_to_gums_object(GUMS_OBJECT
**object
, struct tdbsam2_user_data
*userdata
)
433 NTSTATUS ret
= NT_STATUS_UNSUCCESSFUL
;
436 if (!object
|| !userdata
) {
437 DEBUG(0, ("tdbsam2_user_data_to_gums_object: no NULL pointers are accepted here!\n"));
441 /* userdata->xcounter */
442 /* userdata->sec_desc */
444 SET_OR_FAIL(gums_set_object_sid(*object
, userdata
->user_sid
), error
);
445 SET_OR_FAIL(gums_set_object_name(*object
, userdata
->name
), error
);
447 SET_OR_FAIL(gums_set_user_pri_group(*object
, userdata
->group_sid
), error
);
449 if (userdata
->description
)
450 SET_OR_FAIL(gums_set_object_description(*object
, userdata
->description
), error
);
452 if (userdata
->full_name
)
453 SET_OR_FAIL(gums_set_user_fullname(*object
, userdata
->full_name
), error
);
455 if (userdata
->home_dir
)
456 SET_OR_FAIL(gums_set_user_homedir(*object
, userdata
->home_dir
), error
);
458 if (userdata
->dir_drive
)
459 SET_OR_FAIL(gums_set_user_dir_drive(*object
, userdata
->dir_drive
), error
);
461 if (userdata
->logon_script
)
462 SET_OR_FAIL(gums_set_user_logon_script(*object
, userdata
->logon_script
), error
);
464 if (userdata
->profile_path
)
465 SET_OR_FAIL(gums_set_user_profile_path(*object
, userdata
->profile_path
), error
);
467 if (userdata
->workstations
)
468 SET_OR_FAIL(gums_set_user_workstations(*object
, userdata
->workstations
), error
);
470 if (userdata
->unknown_str
)
471 SET_OR_FAIL(gums_set_user_unknown_str(*object
, userdata
->unknown_str
), error
);
473 if (userdata
->munged_dial
)
474 SET_OR_FAIL(gums_set_user_munged_dial(*object
, userdata
->munged_dial
), error
);
476 SET_OR_FAIL(gums_set_user_logon_divs(*object
, userdata
->logon_divs
), error
);
479 SET_OR_FAIL(gums_set_user_hours(*object
, userdata
->hours_len
, userdata
->hours
), error
);
481 SET_OR_FAIL(gums_set_user_unknown_3(*object
, userdata
->unknown_3
), error
);
482 SET_OR_FAIL(gums_set_user_unknown_5(*object
, userdata
->unknown_5
), error
);
483 SET_OR_FAIL(gums_set_user_unknown_6(*object
, userdata
->unknown_6
), error
);
485 SET_OR_FAIL(gums_set_user_logon_time(*object
, *(userdata
->logon_time
)), error
);
486 SET_OR_FAIL(gums_set_user_logoff_time(*object
, *(userdata
->logoff_time
)), error
);
487 SET_OR_FAIL(gums_set_user_kickoff_time(*object
, *(userdata
->kickoff_time
)), error
);
488 SET_OR_FAIL(gums_set_user_pass_last_set_time(*object
, *(userdata
->pass_last_set_time
)), error
);
489 SET_OR_FAIL(gums_set_user_pass_can_change_time(*object
, *(userdata
->pass_can_change_time
)), error
);
490 SET_OR_FAIL(gums_set_user_pass_must_change_time(*object
, *(userdata
->pass_must_change_time
)), error
);
492 pwd
= data_blob(userdata
->nt_pw_ptr
, NT_HASH_LEN
);
493 ret
= gums_set_user_nt_pwd(*object
, pwd
);
494 data_blob_clear_free(&pwd
);
495 if (!NT_STATUS_IS_OK(ret
)) {
496 DEBUG(5, ("user_data_to_gums_object: failed to set nt password!\n"));
499 pwd
= data_blob(userdata
->lm_pw_ptr
, LM_HASH_LEN
);
500 ret
= gums_set_user_lm_pwd(*object
, pwd
);
501 data_blob_clear_free(&pwd
);
502 if (!NT_STATUS_IS_OK(ret
)) {
503 DEBUG(5, ("user_data_to_gums_object: failed to set lanman password!\n"));
511 talloc_destroy((*object
)->mem_ctx
);
516 static NTSTATUS
group_data_to_gums_object(GUMS_OBJECT
**object
, struct tdbsam2_group_data
*groupdata
)
518 NTSTATUS ret
= NT_STATUS_UNSUCCESSFUL
;
520 if (!object
|| !groupdata
) {
521 DEBUG(0, ("tdbsam2_group_data_to_gums_object: no NULL pointers are accepted here!\n"));
525 /* groupdata->xcounter */
526 /* groupdata->sec_desc */
528 SET_OR_FAIL(gums_set_object_sid(*object
, groupdata
->group_sid
), error
);
529 SET_OR_FAIL(gums_set_object_name(*object
, groupdata
->name
), error
);
531 if (groupdata
->description
)
532 SET_OR_FAIL(gums_set_object_description(*object
, groupdata
->description
), error
);
534 if (groupdata
->count
)
535 SET_OR_FAIL(gums_set_group_members(*object
, groupdata
->count
, groupdata
->members
), error
);
541 talloc_destroy((*object
)->mem_ctx
);
546 static NTSTATUS
domain_data_to_gums_object(GUMS_OBJECT
**object
, struct tdbsam2_domain_data
*domdata
)
549 NTSTATUS ret
= NT_STATUS_UNSUCCESSFUL
;
551 if (!object
|| !*object
|| !domdata
) {
552 DEBUG(0, ("tdbsam2_domain_data_to_gums_object: no NULL pointers are accepted here!\n"));
553 return NT_STATUS_INVALID_PARAMETER
;
556 /* domdata->xcounter */
557 /* domdata->sec_desc */
559 SET_OR_FAIL(gums_set_object_sid(*object
, domdata
->dom_sid
), error
);
560 SET_OR_FAIL(gums_set_object_name(*object
, domdata
->name
), error
);
562 if (domdata
->description
)
563 SET_OR_FAIL(gums_set_object_description(*object
, domdata
->description
), error
);
569 talloc_destroy((*object
)->mem_ctx
);
574 static NTSTATUS
priv_data_to_gums_object(GUMS_OBJECT
**object
, struct tdbsam2_priv_data
*privdata
)
577 NTSTATUS ret
= NT_STATUS_UNSUCCESSFUL
;
579 if (!object
|| !*object
|| !privdata
) {
580 DEBUG(0, ("tdbsam2_priv_data_to_gums_object: no NULL pointers are accepted here!\n"));
584 /* domdata->xcounter */
585 /* domdata->sec_desc */
587 SET_OR_FAIL(gums_set_priv_luid_attr(*object
, privdata
->privilege
), error
);
588 SET_OR_FAIL(gums_set_object_name(*object
, privdata
->name
), error
);
590 if (privdata
->description
)
591 SET_OR_FAIL(gums_set_object_description(*object
, privdata
->description
), error
);
594 SET_OR_FAIL(gums_set_priv_members(*object
, privdata
->count
, privdata
->members
), error
);
600 talloc_destroy((*object
)->mem_ctx
);
605 static NTSTATUS
data_to_gums_object(GUMS_OBJECT
**object
, struct tdbsam2_object
*data
)
610 if (!object
|| !data
) {
611 DEBUG(0, ("tdbsam2_user_data_to_gums_object: no NULL structure pointers are accepted here!\n"));
612 ret
= NT_STATUS_INVALID_PARAMETER
;
616 ret
= gums_create_object(object
, data
->type
);
617 if (!NT_STATUS_IS_OK(ret
)) {
618 DEBUG(5, ("tdbsam2_user_data_to_gums_object: error creating gums object!\n"));
622 switch (data
->type
) {
624 case GUMS_OBJ_DOMAIN
:
625 ret
= domain_data_to_gums_object(object
, data
->data
.domain
);
628 case GUMS_OBJ_NORMAL_USER
:
629 ret
= user_data_to_gums_object(object
, data
->data
.user
);
634 ret
= group_data_to_gums_object(object
, data
->data
.group
);
637 case GUMS_OBJ_PRIVILEGE
:
638 ret
= priv_data_to_gums_object(object
, data
->data
.priv
);
642 ret
= NT_STATUS_UNSUCCESSFUL
;
650 /* GUMM object functions */
652 static NTSTATUS
tdbsam2_get_domain_sid(DOM_SID
*sid
, const char* name
)
661 return NT_STATUS_INVALID_PARAMETER
;
663 if (!NT_STATUS_IS_OK(ret
= opentdb(&tdb
, True
))) {
667 /* Data is stored in all lower-case */
668 fstrcpy(domname
, name
);
671 if (!NT_STATUS_IS_OK(ret
= get_object_by_name(tdb
, &go
, domname
))) {
673 DEBUG(0, ("tdbsam2_get_domain_sid: Error fetching database!\n"));
677 if (gums_get_object_type(go
) != GUMS_OBJ_DOMAIN
) {
678 DEBUG(5, ("tdbsam2_get_domain_sid: Requested object is not a domain!\n"));
679 ret
= NT_STATUS_OBJECT_TYPE_MISMATCH
;
683 sid_copy(sid
, gums_get_object_sid(go
));
689 gums_destroy_object(&go
);
694 static NTSTATUS
get_next_sid(TDB_CONTEXT
*tdb
, DOM_SID
*sid
)
699 TDB_DATA dom_sid_key
;
703 /* Find the domain SID */
704 if (!NT_STATUS_IS_OK(tdbsam2_get_domain_sid(&dom_sid
, global_myname()))) {
705 DEBUG(0, ("get_next_sid: cannot found the domain sid!!\n"));
706 return NT_STATUS_UNSUCCESSFUL
;
709 /* Lock the domain record */
710 sid_to_string(dom_sid_str
, &dom_sid
);
711 dom_sid_key
.dptr
= dom_sid_str
;
712 dom_sid_key
.dsize
= strlen(dom_sid_key
.dptr
) + 1;
714 if(tdb_chainlock(tdb
, dom_sid_key
) != 0) {
715 DEBUG(0, ("get_next_sid: unable to lock domain record!\n"));
716 return NT_STATUS_UNSUCCESSFUL
;
719 /* Get the domain object */
720 ret
= get_object_by_sid(tdb
, &go
, &dom_sid
);
721 if (!NT_STATUS_IS_OK(ret
)) {
722 DEBUG(0, ("get_next_sid: unable to get root Domain object!\n"));
723 ret
= NT_STATUS_INTERNAL_DB_ERROR
;
727 new_rid
= gums_get_domain_next_rid(go
);
729 /* Increment the RID Counter */
730 gums_set_domain_next_rid(go
, new_rid
+1);
732 /* Store back Domain object */
733 ret
= store_object(tdb
, go
, TDB_MODIFY
);
734 if (!NT_STATUS_IS_OK(ret
)) {
735 DEBUG(0, ("get_next_sid: unable to update root Domain object!\n"));
736 ret
= NT_STATUS_INTERNAL_DB_ERROR
;
740 /* Build the Domain SID to return */
741 sid_copy(sid
, &dom_sid
);
743 if (!sid_append_rid(sid
, new_rid
)) {
744 DEBUG(0, ("get_next_sid: unable to build new SID !?!\n"));
745 ret
= NT_STATUS_UNSUCCESSFUL
;
752 /* Unlock the Domain object */
753 tdb_chainunlock(tdb
, dom_sid_key
);
759 NTSTATUS (*get_sequence_number
) (void);
762 extern DOM_SID global_sid_NULL
;
764 static NTSTATUS
tdbsam2_new_object(DOM_SID
*sid
, const char *name
, const int obj_type
)
767 NTSTATUS ret
= NT_STATUS_OK
;
772 const char *defpw
= "NOPASSWORDXXXXXX";
773 uint8 defhours
[21] = {255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255};
776 DEBUG(0, ("tdbsam2_new_object: no NULL pointers are accepted here!\n"));
777 return NT_STATUS_INVALID_PARAMETER
;
780 if (!NT_STATUS_IS_OK(ret
= opentdb(&tdb
, False
))) {
784 if (!NT_STATUS_IS_OK(ret
= gums_create_object(&go
, obj_type
))) {
789 if (obj_type
!= GUMS_OBJ_PRIVILEGE
) {
791 ret
= NT_STATUS_INVALID_PARAMETER
;
795 if (obj_type
== GUMS_OBJ_DOMAIN
) {
796 sid_copy(sid
, get_global_sam_sid());
798 if (!NT_STATUS_IS_OK(ret
= get_next_sid(tdb
, sid
)))
802 gums_set_object_sid(go
, sid
);
805 gums_set_object_name(go
, name
);
806 gums_set_object_seq_num(go
, 1);
808 /*obj.data.domain->sec_desc*/
811 case GUMS_OBJ_NORMAL_USER
:
813 init_nt_time(&null_time
);
815 gums_set_user_logon_time(go
, null_time
);
816 gums_set_user_logoff_time(go
, null_time
);
817 gums_set_user_kickoff_time(go
, null_time
);
818 gums_set_user_pass_last_set_time(go
, null_time
);
819 gums_set_user_pass_can_change_time(go
, null_time
);
820 gums_set_user_pass_must_change_time(go
, null_time
);
822 pw
= data_blob(defpw
, NT_HASH_LEN
);
823 gums_set_user_nt_pwd(go
, pw
);
824 gums_set_user_lm_pwd(go
, pw
);
827 gums_set_user_logon_divs(go
, 168);
828 gums_set_user_hours(go
, 21, defhours
);
830 gums_set_user_unknown_3(go
, 0x00ffffff);
831 gums_set_user_bad_password_count(go
, 0);
832 gums_set_user_logon_count(go
, 0);
833 gums_set_user_unknown_6(go
, 0x000004ec);
841 case GUMS_OBJ_DOMAIN
:
843 gums_set_domain_next_rid(go
, 0x3e9);
847 case GUMS_OBJ_PRIVILEGE
:
852 ret
= NT_STATUS_OBJECT_TYPE_MISMATCH
;
856 ret
= store_object(tdb
, go
, TDB_INSERT
);
860 gums_destroy_object(&go
);
865 static NTSTATUS
tdbsam2_delete_object(const DOM_SID
*sid
)
867 /* TODO: need to address privilege deletion */
868 NTSTATUS ret
= NT_STATUS_OK
;
875 DEBUG(0, ("tdbsam2_delete_object: no NULL pointers are accepted here!\n"));
876 return NT_STATUS_INVALID_PARAMETER
;
879 if (!NT_STATUS_IS_OK(ret
= opentdb(&tdb
, False
))) {
883 slprintf(keystr
, sizeof(keystr
)-1, "%s%s", SIDPREFIX
, sid_string_static(sid
));
885 key
.dsize
= strlen(keystr
) + 1;
887 data
= tdb_fetch(tdb
, key
);
889 DEBUG(5, ("tdbsam2_delete_object: Error fetching database, SID entry not found!\n"));
890 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdb
)));
891 DEBUGADD(5, (" Key: %s\n", keystr
));
892 ret
= NT_STATUS_UNSUCCESSFUL
;
896 if (tdb_delete(tdb
, key
) != TDB_SUCCESS
) {
897 DEBUG(5, ("tdbsam2_delete_object: Error deleting object!\n"));
898 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdb
)));
899 DEBUGADD(5, (" Key: %s\n", keystr
));
900 ret
= NT_STATUS_UNSUCCESSFUL
;
904 if (!NT_STATUS_IS_OK(init_object_from_buffer(&go
, data
.dptr
, data
.dsize
))) {
905 DEBUG(0, ("tdbsam2_delete_object: Error fetching database, malformed entry!\n"));
906 ret
= NT_STATUS_UNSUCCESSFUL
;
911 case GUMS_OBJ_DOMAIN
:
912 /* FIXME: SHOULD WE ALLOW TO DELETE DOMAINS ? */
915 case GUMS_OBJ_NORMAL_USER
:
916 slprintf(keystr
, sizeof(keystr
) - 1, "%s%s", NAMEPREFIX
, gums_get_object_name(go
));
919 ret
= NT_STATUS_OBJECT_TYPE_MISMATCH
;
924 key
.dsize
= strlen(keystr
) + 1;
926 if (tdb_delete(tdb
, key
) != TDB_SUCCESS
) {
927 DEBUG(5, ("tdbsam2_delete_object: Error deleting object!\n"));
928 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdb
)));
929 DEBUGADD(5, (" Key: %s\n", keystr
));
930 ret
= NT_STATUS_UNSUCCESSFUL
;
934 /* TODO: update the general database counter */
937 gums_destroy_object(&go
);
938 SAFE_FREE(data
.dptr
);
942 static NTSTATUS
tdbsam2_get_object_from_sid(GUMS_OBJECT
**object
, const DOM_SID
*sid
, const int obj_type
)
947 if (!object
|| !sid
) {
948 DEBUG(0, ("tdbsam2_get_object_from_sid: no NULL pointers are accepted here!\n"));
949 return NT_STATUS_INVALID_PARAMETER
;
952 if (!NT_STATUS_IS_OK(ret
= opentdb(&tdb
, True
))) {
956 ret
= get_object_by_sid(tdb
, object
, sid
);
957 if (!NT_STATUS_IS_OK(ret
) || (obj_type
&& gums_get_object_type(*object
) != obj_type
)) {
958 DEBUG(0, ("tdbsam2_get_object_from_sid: %s\n", nt_errstr(ret
)));
966 gums_destroy_object(object
);
971 static NTSTATUS
tdbsam2_get_object_from_name(GUMS_OBJECT
**object
, const char *name
, const int obj_type
)
976 if (!object
|| !name
) {
977 DEBUG(0, ("tdbsam2_get_object_from_name: no NULL pointers are accepted here!\n"));
978 return NT_STATUS_INVALID_PARAMETER
;
981 if (!NT_STATUS_IS_OK(ret
= opentdb(&tdb
, True
))) {
986 ret
= get_object_by_name(tdb
, object
, name
);
987 if (!NT_STATUS_IS_OK(ret
) || (obj_type
&& gums_get_object_type(*object
) != obj_type
)) {
988 DEBUG(0, ("tdbsam2_get_object_from_name: %s\n", nt_errstr(ret
)));
996 gums_destroy_object(object
);
1001 /* This function is used to get the list of all objects changed since base_time, it is
1002 used to support PDC<->BDC synchronization */
1003 NTSTATUS (*get_updated_objects
) (GUMS_OBJECT
**objects
, const NTTIME base_time
);
1005 static NTSTATUS
tdbsam2_enumerate_objects_start(void **handle
, const DOM_SID
*sid
, const int obj_type
)
1007 struct tdbsam2_enum_objs
*teo
, *t
;
1009 teo
= (struct tdbsam2_enum_objs
*)malloc(sizeof(struct tdbsam2_enum_objs
));
1011 DEBUG(0, ("tdbsam2_enumerate_objects_start: Out of Memory!\n"));
1012 return NT_STATUS_NO_MEMORY
;
1014 memset(teo
, 0, sizeof(struct tdbsam2_enum_objs
));
1016 teo
->type
= obj_type
;
1018 teo
->dom_sid
= (DOM_SID
*)malloc(sizeof(DOM_SID
));
1019 if (!teo
->dom_sid
) {
1020 DEBUG(0, ("tdbsam2_enumerate_objects_start: Out of Memory!\n"));
1021 return NT_STATUS_NO_MEMORY
;
1023 sid_copy(teo
->dom_sid
, sid
);
1026 if (!NT_STATUS_IS_OK(opentdb(&(teo
->db
), True
)))
1028 DEBUG(0, ("tdbsam2_enumerate_objects_start: Unable to open database (%s)!\n", ts2_privs
->storage
));
1030 return NT_STATUS_UNSUCCESSFUL
;
1033 if (!ts2_privs
->teo_handlers
) {
1034 ts2_privs
->teo_handlers
= teo
;
1036 t
= ts2_privs
->teo_handlers
;
1045 teo
->key
= tdb_firstkey(teo
->db
);
1047 return NT_STATUS_OK
;
1050 static NTSTATUS
tdbsam2_enumerate_objects_get_next(GUMS_OBJECT
**object
, void *handle
)
1054 struct tdbsam2_enum_objs
*teo
;
1055 const char *prefix
= SIDPREFIX
;
1056 const int preflen
= strlen(prefix
);
1057 fstring dom_sid_str
;
1058 int dom_sid_str_len
= 0;
1060 if (!object
|| !handle
) {
1061 DEBUG(0, ("tdbsam2_get_object_from_sid: no NULL pointers are accepted here!\n"));
1062 return NT_STATUS_INVALID_PARAMETER
;
1065 teo
= (struct tdbsam2_enum_objs
*)handle
;
1068 sid_to_string(dom_sid_str
, teo
->dom_sid
);
1069 dom_sid_str_len
= strlen(dom_sid_str
);
1072 while ((teo
->key
.dptr
!= NULL
)) {
1073 int len
, version
, type
, size
;
1076 if (strncmp(teo
->key
.dptr
, prefix
, preflen
)) {
1077 teo
->key
= tdb_nextkey(teo
->db
, teo
->key
);
1081 if (dom_sid_str_len
!= 0) {
1082 if (strncmp(&(teo
->key
.dptr
[preflen
]), dom_sid_str
, dom_sid_str_len
)) {
1083 teo
->key
= tdb_nextkey(teo
->db
, teo
->key
);
1088 data
= tdb_fetch(teo
->db
, teo
->key
);
1090 DEBUG(5, ("tdbsam2_enumerate_objects_get_next: Error fetching database, SID entry not found!\n"));
1091 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(teo
->db
)));
1092 DEBUGADD(5, (" Key: %s\n", teo
->key
.dptr
));
1093 ret
= NT_STATUS_UNSUCCESSFUL
;
1097 len
= tdb_unpack (data
.dptr
, data
.dsize
, TDB_FORMAT_STRING
,
1103 DEBUG(5, ("tdbsam2_enumerate_objects_get_next: Error unable to unpack data!\n"));
1104 ret
= NT_STATUS_UNSUCCESSFUL
;
1109 if (teo
->type
&& type
!= teo
->type
) {
1110 SAFE_FREE(data
.dptr
);
1112 teo
->key
= tdb_nextkey(teo
->db
, teo
->key
);
1119 if (teo
->key
.dptr
== NULL
) { /* no more objs */
1120 ret
= NT_STATUS_NO_MORE_ENTRIES
;
1124 if (!NT_STATUS_IS_OK(ret
= init_object_from_buffer(object
, data
.dptr
, data
.dsize
))) {
1125 SAFE_FREE(data
.dptr
);
1126 DEBUG(0, ("tdbsam2_enumerate_objects_get_next: Error fetching database, malformed entry!\n"));
1127 ret
= NT_STATUS_UNSUCCESSFUL
;
1130 SAFE_FREE(data
.dptr
);
1132 /* prepare next run */
1133 teo
->key
= tdb_nextkey(teo
->db
, teo
->key
);
1139 static NTSTATUS
tdbsam2_enumerate_objects_stop(void *handle
)
1141 struct tdbsam2_enum_objs
*teo
, *t
, *p
;
1143 teo
= (struct tdbsam2_enum_objs
*)handle
;
1145 if (ts2_privs
->teo_handlers
== teo
) {
1146 ts2_privs
->teo_handlers
= teo
->next
;
1148 t
= ts2_privs
->teo_handlers
;
1153 DEBUG(0, ("tdbsam2_enumerate_objects_stop: Error, handle not found!\n"));
1154 return NT_STATUS_UNSUCCESSFUL
;
1161 SAFE_FREE(teo
->dom_sid
);
1164 return NT_STATUS_OK
;
1167 static NTSTATUS
tdbsam2_set_object(const GUMS_OBJECT
*go
)
1173 return NT_STATUS_INVALID_PARAMETER
;
1175 if (!NT_STATUS_IS_OK(ret
= opentdb(&tdb
, False
))) {
1179 ret
= store_object(tdb
, go
, TDB_REPLACE
);
1185 /* set object values function */
1186 static NTSTATUS (*set_object_values
) (DOM_SID
*sid
, uint32 count
, GUMS_DATA_SET
*data_set
);
1188 /* Group related functions */
1189 static NTSTATUS (*add_memberss_to_group
) (const DOM_SID
*group
, const DOM_SID
**members
);
1190 NTSTATUS (*delete_members_from_group
) (const DOM_SID
*group
, const DOM_SID
**members
);
1191 static NTSTATUS (*enumerate_group_members
) (DOM_SID
**members
, const DOM_SID
*sid
, const int type
);
1193 static NTSTATUS (*get_sid_groups
) (DOM_SID
**groups
, const DOM_SID
*sid
);
1195 static NTSTATUS (*lock_sid
) (const DOM_SID
*sid
);
1196 static NTSTATUS (*unlock_sid
) (const DOM_SID
*sid
);
1198 /* privileges related functions */
1200 static NTSTATUS (*add_members_to_privilege
) (const LUID_ATTR
*priv
, const DOM_SID
**members
);
1201 static NTSTATUS (*delete_members_from_privilege
) (const LUID_ATTR
*priv
, const DOM_SID
**members
);
1202 static NTSTATUS (*enumerate_privilege_members
) (DOM_SID
**members
, const LUID_ATTR
*priv
);
1203 static NTSTATUS (*get_sid_privileges
) (DOM_SID
**privs
, const DOM_SID
*sid
);
1204 /* warning!: set_privilege will overwrite a prior existing privilege if such exist */
1205 static NTSTATUS (*set_privilege
) (GUMS_PRIVILEGE
*priv
);
1207 static void free_tdbsam2_private_data(void **vp
)
1209 struct tdbsam2_private_data
**tdb_privs
= (struct tdbsam2_private_data
**)vp
;
1210 while (ts2_privs
->teo_handlers
)
1211 tdbsam2_enumerate_objects_stop(ts2_privs
->teo_handlers
);
1213 /* No need to free any further, as it is talloc()ed */
1216 static NTSTATUS
init_tdbsam2(GUMS_FUNCTIONS
*fns
, const char *storage
)
1222 fns
->name
= talloc_strdup(fns
->mem_ctx
, "tdbsam2");
1224 fns
->get_domain_sid
= tdbsam2_get_domain_sid
;
1225 /* fns->get_sequence_number = tdbsam2_get_sequence_number; */
1226 fns
->new_object
= tdbsam2_new_object
;
1227 fns
->delete_object
= tdbsam2_delete_object
;
1228 fns
->get_object_from_sid
= tdbsam2_get_object_from_sid
;
1229 fns
->get_object_from_name
= tdbsam2_get_object_from_name
;
1230 /* fns->get_updated_objects = tdbsam2_get_updated_objects; */
1231 fns
->enumerate_objects_start
= tdbsam2_enumerate_objects_start
;
1232 fns
->enumerate_objects_get_next
= tdbsam2_enumerate_objects_get_next
;
1233 fns
->enumerate_objects_stop
= tdbsam2_enumerate_objects_stop
;
1234 fns
->set_object
= tdbsam2_set_object
;
1235 /* fns->set_object_values = tdbsam2_set_object_values;
1236 fns->add_members_to_group = tdbsam2_add_members_to_group;
1237 fns->delete_members_from_group = tdbsam2_delete_members_from_group;
1238 fns->enumerate_group_members = tdbsam2_enumerate_group_members;
1239 fns->get_sid_groups = tdbsam2_get_sid_groups;
1240 fns->lock_sid = tdbsam2_lock_sid;
1241 fns->unlock_sid = tdbsam2_unlock_sid;
1242 fns->add_members_to_privilege = tdbsam2_add_members_to_privilege;
1243 fns->delete_members_from_privilege = tdbsam2_delete_members_from_privilege;
1244 fns->enumerate_privilege_members = tdbsam2_enumerate_privilege_members;
1245 fns->get_sid_privileges = tdbsam2_get_sid_privileges;
1246 fns->set_privilege = tdbsam2_set_privilege; */
1248 ts2_privs
= talloc_zero(fns
->mem_ctx
, sizeof(struct tdbsam2_private_data
));
1250 DEBUG(0, ("talloc() failed for tdbsam2 private_data!\n"));
1251 return NT_STATUS_NO_MEMORY
;
1255 ts2_privs
->storage
= talloc_strdup(fns
->mem_ctx
, storage
);
1258 get_private_directory(tdbfile
);
1259 pstrcat(tdbfile
, "/");
1260 pstrcat(tdbfile
, TDB_FILE_NAME
);
1261 ts2_privs
->storage
= talloc_strdup(fns
->mem_ctx
, tdbfile
);
1264 /* check tdb exist (or create it) */
1266 /* Find the domain SID */
1267 if (!NT_STATUS_IS_OK(tdbsam2_get_domain_sid(&dom_sid
, global_myname()))) {
1268 /* db file does not exist or it is not inited */
1269 /* make the tdb file */
1270 if (!NT_STATUS_IS_OK(ret
= opentdb(&tdb
, False
))) {
1275 if (!NT_STATUS_IS_OK(tdbsam2_get_domain_sid(&dom_sid
, "BUILTIN"))) {
1276 gums_init_builtin_domain();
1279 gums_init_domain(get_global_sam_sid(), global_myname());
1282 fns
->private_data
= &ts2_privs
;
1283 fns
->free_private_data
= free_tdbsam2_private_data
;
1285 return NT_STATUS_OK
;
1288 NTSTATUS
gums_tdbsam2_init(void)
1291 if ((gums_tdbsam2_debug_class = debug_add_class("gums_tdbsam2")) == -1) {
1292 DEBUG(0, ("gums_tdbsam2: unable to register my own debug class! going on ...\n"));
1293 gums_tdbsam2_debug_class = DBGC_ALL;
1296 return gums_register_module(GUMS_INTERFACE_VERSION
, "tdbsam2", init_tdbsam2
);