2 * Unix SMB/CIFS implementation.
3 * SMB parameters and setup
4 * Copyright (C) Andrew Tridgell 1992-1998
5 * Copyright (C) Simo Sorce 2000-2002
6 * Copyright (C) Gerald Carter 2000
7 * Copyright (C) Jeremy Allison 2001
8 * Copyright (C) Andrew Bartlett 2002
10 * This program is free software; you can redistribute it and/or modify it under
11 * the terms of the GNU General Public License as published by the Free
12 * Software Foundation; either version 2 of the License, or (at your option)
15 * This program is distributed in the hope that it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
20 * You should have received a copy of the GNU General Public License along with
21 * this program; if not, write to the Free Software Foundation, Inc., 675
22 * Mass Ave, Cambridge, MA 02139, USA.
27 #include "tdbsam2_parse_info.h"
29 static int tdbgumm_debug_level
= DBGC_ALL
;
31 #define DBGC_CLASS tdbgumm_debug_level
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_ERR(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
;
58 struct tdbsam2_object
{
61 union tdbsam2_data data
;
64 static TDB_CONTEXT
*tdbsam2_db
;
66 struct tdbsam2_enum_objs
**teo_handlers
;
68 static NTSTATUS
init_tdbsam2_object_from_buffer(struct tdbsam2_object
*object
, TALLOC_CTX
*mem_ctx
, char *buffer
, int size
)
71 NTSTATUS ret
= NT_STATUS_UNSUCCESSFUL
;
77 len
= tdb_unpack (buffer
, size
, TDB_FORMAT_STRING
,
80 &data_size
, &obj_data
);
85 /* version is checked inside this function so that backward compatibility code can be
87 this way we can easily handle database format upgrades */
88 if (object
->version
!= TDBSAM_VERSION
) {
89 DEBUG(3,("init_tdbsam2_object_from_buffer: Error, db object has wrong tdbsam version!\n"));
93 /* be sure the string is terminated before trying to parse it */
94 if (obj_data
[data_size
- 1] != '\0')
95 obj_data
[data_size
- 1] = '\0';
97 switch (object
->type
) {
99 object
->data
.domain
= (struct tdbsam2_domain_data
*)talloc(mem_ctx
, sizeof(struct tdbsam2_domain_data
));
100 TALLOC_CHECK(object
->data
.domain
, ret
, done
);
101 memset(object
->data
.domain
, 0, sizeof(struct tdbsam2_domain_data
));
103 iret
= gen_parse(mem_ctx
, pinfo_tdbsam2_domain_data
, (char *)(object
->data
.domain
), obj_data
);
107 object
->data
.group
= (struct tdbsam2_group_data
*)talloc(mem_ctx
, sizeof(struct tdbsam2_group_data
));
108 TALLOC_CHECK(object
->data
.group
, ret
, done
);
109 memset(object
->data
.group
, 0, sizeof(struct tdbsam2_group_data
));
111 iret
= gen_parse(mem_ctx
, pinfo_tdbsam2_group_data
, (char *)(object
->data
.group
), obj_data
);
113 case GUMS_OBJ_NORMAL_USER
:
114 object
->data
.user
= (struct tdbsam2_user_data
*)talloc(mem_ctx
, sizeof(struct tdbsam2_user_data
));
115 TALLOC_CHECK(object
->data
.user
, ret
, done
);
116 memset(object
->data
.user
, 0, sizeof(struct tdbsam2_user_data
));
118 iret
= gen_parse(mem_ctx
, pinfo_tdbsam2_user_data
, (char *)(object
->data
.user
), obj_data
);
121 DEBUG(3,("init_tdbsam2_object_from_buffer: Error, wrong object type number!\n"));
126 DEBUG(0,("init_tdbsam2_object_from_buffer: Fatal Error! Unable to parse object!\n"));
127 DEBUG(0,("init_tdbsam2_object_from_buffer: DB Corrupted ?"));
137 static NTSTATUS
init_buffer_from_tdbsam2_object(char **buffer
, size_t *len
, TALLOC_CTX
*mem_ctx
, struct tdbsam2_object
*object
)
145 return NT_STATUS_INVALID_PARAMETER
;
147 switch (object
->type
) {
148 case GUMS_OBJ_DOMAIN
:
149 buf1
= gen_dump(mem_ctx
, pinfo_tdbsam2_domain_data
, (char *)(object
->data
.domain
), 0);
153 buf1
= gen_dump(mem_ctx
, pinfo_tdbsam2_group_data
, (char *)(object
->data
.group
), 0);
155 case GUMS_OBJ_NORMAL_USER
:
156 buf1
= gen_dump(mem_ctx
, pinfo_tdbsam2_user_data
, (char *)(object
->data
.user
), 0);
159 DEBUG(3,("init_buffer_from_tdbsam2_object: Error, wrong object type number!\n"));
160 return NT_STATUS_UNSUCCESSFUL
;
164 DEBUG(0, ("init_buffer_from_tdbsam2_object: Fatal Error! Unable to dump object!\n"));
165 return NT_STATUS_UNSUCCESSFUL
;
168 buflen
= tdb_pack(NULL
, 0, TDB_FORMAT_STRING
,
171 strlen(buf1
) + 1, buf1
);
173 *buffer
= talloc(mem_ctx
, buflen
);
174 TALLOC_CHECK(*buffer
, ret
, done
);
176 *len
= tdb_pack(*buffer
, buflen
, TDB_FORMAT_STRING
,
179 strlen(buf1
) + 1, buf1
);
181 if (*len
!= buflen
) {
182 DEBUG(0, ("init_tdb_data_from_tdbsam2_object: somthing odd is going on here: bufflen (%d) != len (%d) in tdb_pack operations!\n",
185 ret
= NT_STATUS_UNSUCCESSFUL
;
194 static NTSTATUS
opentdb(void)
198 get_private_directory(tdbfile
);
199 pstrcat(tdbfile
, "/");
200 pstrcat(tdbfile
, TDB_FILE_NAME
);
202 tdbsam2_db
= tdb_open_log(tdbfile
, 0, TDB_DEFAULT
, O_RDWR
| O_CREAT
, 0600);
205 DEBUG(0, ("opentdb: Unable to open database (%s)!\n", tdbfile
));
206 return NT_STATUS_UNSUCCESSFUL
;
213 static NTSTATUS
get_object_by_sid(TALLOC_CTX
*mem_ctx
, struct tdbsam2_object
*obj
, const DOM_SID
*sid
)
219 if (!obj
|| !mem_ctx
|| !sid
)
220 return NT_STATUS_INVALID_PARAMETER
;
222 if (NT_STATUS_IS_ERR(ret
= opentdb())) {
226 slprintf(keystr
, sizeof(keystr
)-1, "%s%s", SIDPREFIX
, sid_string_static(sid
));
228 key
.dsize
= strlen(keystr
) + 1;
230 data
= tdb_fetch(tdbsam2_db
, key
);
232 DEBUG(5, ("get_object_by_sid: Error fetching database, domain entry not found!\n"));
233 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam2_db
)));
234 DEBUGADD(5, (" Key: %s\n", keystr
));
235 return NT_STATUS_UNSUCCESSFUL
;
238 if (NT_STATUS_IS_ERR(init_tdbsam2_object_from_buffer(obj
, mem_ctx
, data
.dptr
, data
.dsize
))) {
239 SAFE_FREE(data
.dptr
);
240 DEBUG(0, ("get_object_by_sid: Error fetching database, malformed entry!\n"));
241 return NT_STATUS_UNSUCCESSFUL
;
243 SAFE_FREE(data
.dptr
);
249 static NTSTATUS
get_object_by_name(TALLOC_CTX
*mem_ctx
, struct tdbsam2_object
*obj
, const char* name
)
258 int obj_version
, obj_type
, obj_sidstr_len
, len
;
260 if (!obj
|| !mem_ctx
|| !name
)
261 return NT_STATUS_INVALID_PARAMETER
;
263 if (NT_STATUS_IS_ERR(ret
= opentdb())) {
267 fstrcpy(objname
, name
);
270 slprintf(keystr
, sizeof(keystr
)-1, "%s%s", NAMEPREFIX
, objname
);
272 key
.dsize
= strlen(keystr
) + 1;
274 data
= tdb_fetch(tdbsam2_db
, key
);
276 DEBUG(5, ("get_object_by_name: Error fetching database, domain entry not found!\n"));
277 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam2_db
)));
278 DEBUGADD(5, (" Key: %s\n", keystr
));
279 return NT_STATUS_UNSUCCESSFUL
;
282 len
= tdb_unpack(data
.dptr
, data
.dsize
, TDB_FORMAT_STRING
,
285 &obj_sidstr_len
, &obj_sidstr
);
287 SAFE_FREE(data
.dptr
);
289 if (len
== -1 || obj_version
!= TDBSAM_VERSION
|| obj_sidstr_len
<= 0) {
290 DEBUG(5, ("get_object_by_name: Error unpacking database object!\n"));
291 return NT_STATUS_UNSUCCESSFUL
;
294 if (!string_to_sid(&sid
, obj_sidstr
)) {
295 DEBUG(5, ("get_object_by_name: Error invalid sid string found in database object!\n"));
296 SAFE_FREE(obj_sidstr
);
297 return NT_STATUS_UNSUCCESSFUL
;
299 SAFE_FREE(obj_sidstr
);
301 return get_object_by_sid(mem_ctx
, obj
, &sid
);
304 static NTSTATUS
store_object(TALLOC_CTX
*mem_ctx
, struct tdbsam2_object
*object
, BOOL new_obj
)
308 TDB_DATA data
, key
, key2
;
313 if (NT_STATUS_IS_ERR(ret
= opentdb())) {
323 ret
= init_buffer_from_tdbsam2_object(&(data
.dptr
), &(data
.dsize
), mem_ctx
, object
);
324 if (NT_STATUS_IS_ERR(ret
))
327 switch (object
->type
) {
328 case GUMS_OBJ_DOMAIN
:
329 slprintf(keystr
, sizeof(keystr
) - 1, "%s%s", SIDPREFIX
, sid_string_static(object
->data
.domain
->dom_sid
));
330 slprintf(namestr
, sizeof(namestr
) - 1, "%s%s", NAMEPREFIX
, object
->data
.domain
->name
);
334 slprintf(keystr
, sizeof(keystr
) - 1, "%s%s", SIDPREFIX
, sid_string_static(object
->data
.group
->group_sid
));
335 slprintf(namestr
, sizeof(namestr
) - 1, "%s%s", NAMEPREFIX
, object
->data
.group
->name
);
337 case GUMS_OBJ_NORMAL_USER
:
338 slprintf(keystr
, sizeof(keystr
) - 1, "%s%s", SIDPREFIX
, sid_string_static(object
->data
.user
->user_sid
));
339 slprintf(namestr
, sizeof(namestr
) - 1, "%s%s", NAMEPREFIX
, object
->data
.user
->name
);
342 return NT_STATUS_UNSUCCESSFUL
;
346 key
.dsize
= strlen(keystr
) + 1;
348 if ((r
= tdb_store(tdbsam2_db
, key
, data
, flag
)) != TDB_SUCCESS
) {
349 DEBUG(0, ("store_object: Unable to modify SAM!\n"));
350 DEBUGADD(0, (" Error: %s", tdb_errorstr(tdbsam2_db
)));
351 DEBUGADD(0, (" occured while storing the main record (%s)\n", keystr
));
352 if (r
== TDB_ERR_EXISTS
) return NT_STATUS_UNSUCCESSFUL
;
353 return NT_STATUS_INTERNAL_DB_ERROR
;
357 key2
.dsize
= strlen(namestr
) + 1;
359 if ((r
= tdb_store(tdbsam2_db
, key2
, key
, flag
)) != TDB_SUCCESS
) {
360 DEBUG(0, ("store_object: Unable to modify SAM!\n"));
361 DEBUGADD(0, (" Error: %s", tdb_errorstr(tdbsam2_db
)));
362 DEBUGADD(0, (" occured while storing the main record (%s)\n", keystr
));
363 if (r
== TDB_ERR_EXISTS
) return NT_STATUS_UNSUCCESSFUL
;
364 return NT_STATUS_INTERNAL_DB_ERROR
;
366 /* TODO: update the general database counter */
367 /* TODO: update this entry counter too */
372 static NTSTATUS
get_next_sid(TALLOC_CTX
*mem_ctx
, DOM_SID
**sid
)
375 struct tdbsam2_object obj
;
376 DOM_SID
*dom_sid
= get_global_sam_sid();
379 /* TODO: LOCK DOMAIN OBJECT */
380 ret
= get_object_by_sid(mem_ctx
, &obj
, dom_sid
);
381 if (NT_STATUS_IS_ERR(ret
)) {
382 DEBUG(0, ("get_next_sid: unable to get root Domain object!\n"));
383 ret
= NT_STATUS_INTERNAL_DB_ERROR
;
387 new_rid
= obj
.data
.domain
->next_rid
;
389 /* Increment the RID Counter */
390 obj
.data
.domain
->next_rid
++;
392 /* Store back Domain object */
393 ret
= store_object(mem_ctx
, &obj
, False
);
394 if (NT_STATUS_IS_ERR(ret
)) {
395 DEBUG(0, ("get_next_sid: unable to update root Domain object!\n"));
396 ret
= NT_STATUS_INTERNAL_DB_ERROR
;
399 /* TODO: UNLOCK DOMAIN OBJECT */
401 *sid
= sid_dup_talloc(mem_ctx
, dom_sid
);
402 TALLOC_CHECK(*sid
, ret
, error
);
404 if (!sid_append_rid(*sid
, new_rid
)) {
405 DEBUG(0, ("get_next_sid: unable to build new SID !?!\n"));
406 ret
= NT_STATUS_UNSUCCESSFUL
;
416 static NTSTATUS
user_data_to_gums_object(GUMS_OBJECT
**object
, struct tdbsam2_user_data
*userdata
)
420 if (!object
|| !userdata
) {
421 DEBUG(0, ("tdbsam2_user_data_to_gums_object: no NULL pointers are accepted here!\n"));
422 return NT_STATUS_UNSUCCESSFUL
;
425 /* userdata->xcounter */
426 /* userdata->sec_desc */
428 SET_OR_FAIL(gums_set_object_sid(*object
, userdata
->user_sid
), error
);
429 SET_OR_FAIL(gums_set_object_name(*object
, userdata
->name
), error
);
431 SET_OR_FAIL(gums_set_user_pri_group(*object
, userdata
->group_sid
), error
);
433 if (userdata
->description
)
434 SET_OR_FAIL(gums_set_object_description(*object
, userdata
->description
), error
);
436 if (userdata
->full_name
)
437 SET_OR_FAIL(gums_set_user_fullname(*object
, userdata
->full_name
), error
);
439 if (userdata
->home_dir
)
440 SET_OR_FAIL(gums_set_user_homedir(*object
, userdata
->home_dir
), error
);
442 if (userdata
->dir_drive
)
443 SET_OR_FAIL(gums_set_user_dir_drive(*object
, userdata
->dir_drive
), error
);
445 if (userdata
->logon_script
)
446 SET_OR_FAIL(gums_set_user_logon_script(*object
, userdata
->logon_script
), error
);
448 if (userdata
->profile_path
)
449 SET_OR_FAIL(gums_set_user_profile_path(*object
, userdata
->profile_path
), error
);
451 if (userdata
->workstations
)
452 SET_OR_FAIL(gums_set_user_workstations(*object
, userdata
->workstations
), error
);
454 if (userdata
->unknown_str
)
455 SET_OR_FAIL(gums_set_user_unknown_str(*object
, userdata
->unknown_str
), error
);
457 if (userdata
->munged_dial
)
458 SET_OR_FAIL(gums_set_user_munged_dial(*object
, userdata
->munged_dial
), error
);
460 SET_OR_FAIL(gums_set_user_logon_divs(*object
, userdata
->logon_divs
), error
);
461 SET_OR_FAIL(gums_set_user_hours_len(*object
, userdata
->hours_len
), error
);
464 SET_OR_FAIL(gums_set_user_hours(*object
, userdata
->hours
), error
);
466 SET_OR_FAIL(gums_set_user_unknown_3(*object
, userdata
->unknown_3
), error
);
467 SET_OR_FAIL(gums_set_user_bad_password_count(*object
, userdata
->bad_password_count
), error
);
468 SET_OR_FAIL(gums_set_user_unknown_6(*object
, userdata
->unknown_6
), error
);
470 SET_OR_FAIL(gums_set_user_logon_time(*object
, *(userdata
->logon_time
)), error
);
471 SET_OR_FAIL(gums_set_user_logoff_time(*object
, *(userdata
->logoff_time
)), error
);
472 SET_OR_FAIL(gums_set_user_kickoff_time(*object
, *(userdata
->kickoff_time
)), error
);
473 SET_OR_FAIL(gums_set_user_pass_last_set_time(*object
, *(userdata
->pass_last_set_time
)), error
);
474 SET_OR_FAIL(gums_set_user_pass_can_change_time(*object
, *(userdata
->pass_can_change_time
)), error
);
475 SET_OR_FAIL(gums_set_user_pass_must_change_time(*object
, *(userdata
->pass_must_change_time
)), error
);
481 talloc_destroy((*object
)->mem_ctx
);
486 static NTSTATUS
group_data_to_gums_object(GUMS_OBJECT
**object
, struct tdbsam2_group_data
*groupdata
)
490 if (!object
|| !groupdata
) {
491 DEBUG(0, ("tdbsam2_group_data_to_gums_object: no NULL pointers are accepted here!\n"));
492 return NT_STATUS_UNSUCCESSFUL
;
495 /* groupdata->xcounter */
496 /* groupdata->sec_desc */
498 SET_OR_FAIL(gums_set_object_sid(*object
, groupdata
->group_sid
), error
);
499 SET_OR_FAIL(gums_set_object_name(*object
, groupdata
->name
), error
);
501 if (groupdata
->description
)
502 SET_OR_FAIL(gums_set_object_description(*object
, groupdata
->description
), error
);
504 if (groupdata
->count
)
505 SET_OR_FAIL(gums_set_group_members(*object
, groupdata
->count
, groupdata
->members
), error
);
511 talloc_destroy((*object
)->mem_ctx
);
516 static NTSTATUS
domain_data_to_gums_object(GUMS_OBJECT
**object
, struct tdbsam2_domain_data
*domdata
)
521 if (!object
|| !*object
|| !domdata
) {
522 DEBUG(0, ("tdbsam2_domain_data_to_gums_object: no NULL pointers are accepted here!\n"));
523 return NT_STATUS_UNSUCCESSFUL
;
526 /* domdata->xcounter */
527 /* domdata->sec_desc */
529 SET_OR_FAIL(gums_set_object_sid(*object
, domdata
->dom_sid
), error
);
530 SET_OR_FAIL(gums_set_object_name(*object
, domdata
->name
), error
);
532 if (domdata
->description
)
533 SET_OR_FAIL(gums_set_object_description(*object
, domdata
->description
), error
);
539 talloc_destroy((*object
)->mem_ctx
);
544 static NTSTATUS
data_to_gums_object(GUMS_OBJECT
**object
, struct tdbsam2_object
*data
)
549 if (!object
|| !data
) {
550 DEBUG(0, ("tdbsam2_user_data_to_gums_object: no NULL structure pointers are accepted here!\n"));
551 ret
= NT_STATUS_INVALID_PARAMETER
;
555 ret
= gums_create_object(object
, data
->type
);
556 if (NT_STATUS_IS_ERR(ret
)) {
557 DEBUG(5, ("tdbsam2_user_data_to_gums_object: error creating gums object!\n"));
561 switch (data
->type
) {
562 case GUMS_OBJ_DOMAIN
:
563 ret
= domain_data_to_gums_object(object
, data
->data
.domain
);
566 case GUMS_OBJ_NORMAL_USER
:
567 ret
= user_data_to_gums_object(object
, data
->data
.user
);
572 ret
= group_data_to_gums_object(object
, data
->data
.group
);
576 ret
= NT_STATUS_UNSUCCESSFUL
;
584 /* GUMM object functions */
586 static NTSTATUS
tdbsam2_get_domain_sid(DOM_SID
*sid
, const char* name
)
590 struct tdbsam2_object obj
;
595 return NT_STATUS_INVALID_PARAMETER
;
597 mem_ctx
= talloc_init("tdbsam2_get_domain_sid");
599 DEBUG(0, ("tdbsam2_new_object: Out of memory!\n"));
600 return NT_STATUS_NO_MEMORY
;
603 if (NT_STATUS_IS_ERR(ret
= opentdb())) {
607 fstrcpy(domname
, name
);
610 ret
= get_object_by_name(mem_ctx
, &obj
, domname
);
612 if (NT_STATUS_IS_ERR(ret
)) {
613 DEBUG(0, ("tdbsam2_get_domain_sid: Error fetching database!\n"));
617 if (obj
.type
!= GUMS_OBJ_DOMAIN
) {
618 DEBUG(5, ("tdbsam2_get_domain_sid: Requested object is not a domain!\n"));
619 ret
= NT_STATUS_UNSUCCESSFUL
;
623 sid_copy(sid
, obj
.data
.domain
->dom_sid
);
628 talloc_destroy(mem_ctx
);
632 static NTSTATUS
tdbsam2_set_domain_sid (const DOM_SID
*sid
, const char *name
)
636 struct tdbsam2_object obj
;
641 return NT_STATUS_INVALID_PARAMETER
;
643 mem_ctx
= talloc_init("tdbsam2_set_domain_sid");
645 DEBUG(0, ("tdbsam2_new_object: Out of memory!\n"));
646 return NT_STATUS_NO_MEMORY
;
649 if (tdbsam2_db
== NULL
) {
650 if (NT_STATUS_IS_ERR(ret
= opentdb())) {
655 fstrcpy(domname
, name
);
658 /* TODO: we need to lock this entry until updated! */
660 ret
= get_object_by_name(mem_ctx
, &obj
, domname
);
662 if (NT_STATUS_IS_ERR(ret
)) {
663 DEBUG(0, ("tdbsam2_get_domain_sid: Error fetching database!\n"));
667 if (obj
.type
!= GUMS_OBJ_DOMAIN
) {
668 DEBUG(5, ("tdbsam2_get_domain_sid: Requested object is not a domain!\n"));
669 ret
= NT_STATUS_UNSUCCESSFUL
;
673 sid_copy(obj
.data
.domain
->dom_sid
, sid
);
675 ret
= store_object(mem_ctx
, &obj
, False
);
678 /* TODO: unlock here */
679 if (mem_ctx
) talloc_destroy(mem_ctx
);
684 NTSTATUS (*get_sequence_number
) (void);
687 extern DOM_SID global_sid_NULL
;
689 static NTSTATUS
tdbsam2_new_object(DOM_SID
*sid
, const char *name
, const int obj_type
)
693 struct tdbsam2_object obj
;
695 NTTIME zero_time
= {0,0};
696 const char *defpw
= "NOPASSWORDXXXXXX";
697 uint8 defhours
[21] = {255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255};
700 DEBUG(0, ("tdbsam2_new_object: no NULL pointers are accepted here!\n"));
701 return NT_STATUS_INVALID_PARAMETER
;
704 mem_ctx
= talloc_init("tdbsam2_new_object");
706 DEBUG(0, ("tdbsam2_new_object: Out of memory!\n"));
707 return NT_STATUS_NO_MEMORY
;
711 obj
.version
= TDBSAM_VERSION
;
714 case GUMS_OBJ_NORMAL_USER
:
715 obj
.data
.user
= (struct tdbsam2_user_data
*)talloc_zero(mem_ctx
, sizeof(struct tdbsam2_user_data
));
716 TALLOC_CHECK(obj
.data
.user
, ret
, done
);
718 get_next_sid(mem_ctx
, &(obj
.data
.user
->user_sid
));
719 TALLOC_CHECK(obj
.data
.user
->user_sid
, ret
, done
);
720 sid_copy(sid
, obj
.data
.user
->user_sid
);
722 obj
.data
.user
->name
= talloc_strdup(mem_ctx
, name
);
723 TALLOC_CHECK(obj
.data
.user
, ret
, done
);
725 obj
.data
.user
->xcounter
= 1;
726 /*obj.data.user->sec_desc*/
727 obj
.data
.user
->description
= "";
728 obj
.data
.user
->group_sid
= &global_sid_NULL
;
729 obj
.data
.user
->logon_time
= &zero_time
;
730 obj
.data
.user
->logoff_time
= &zero_time
;
731 obj
.data
.user
->kickoff_time
= &zero_time
;
732 obj
.data
.user
->pass_last_set_time
= &zero_time
;
733 obj
.data
.user
->pass_can_change_time
= &zero_time
;
734 obj
.data
.user
->pass_must_change_time
= &zero_time
;
736 obj
.data
.user
->full_name
= "";
737 obj
.data
.user
->home_dir
= "";
738 obj
.data
.user
->dir_drive
= "";
739 obj
.data
.user
->logon_script
= "";
740 obj
.data
.user
->profile_path
= "";
741 obj
.data
.user
->workstations
= "";
742 obj
.data
.user
->unknown_str
= "";
743 obj
.data
.user
->munged_dial
= "";
745 obj
.data
.user
->lm_pw_ptr
= defpw
;
746 obj
.data
.user
->nt_pw_ptr
= defpw
;
748 obj
.data
.user
->logon_divs
= 168;
749 obj
.data
.user
->hours_len
= 21;
750 obj
.data
.user
->hours
= &defhours
;
752 obj
.data
.user
->unknown_3
= 0x00ffffff;
753 obj
.data
.user
->bad_password_count
= 0x00020000;
754 obj
.data
.user
->unknown_6
= 0x000004ec;
759 obj
.data
.group
= (struct tdbsam2_group_data
*)talloc_zero(mem_ctx
, sizeof(struct tdbsam2_group_data
));
760 TALLOC_CHECK(obj
.data
.group
, ret
, done
);
762 get_next_sid(mem_ctx
, &(obj
.data
.group
->group_sid
));
763 TALLOC_CHECK(obj
.data
.group
->group_sid
, ret
, done
);
764 sid_copy(sid
, obj
.data
.group
->group_sid
);
766 obj
.data
.group
->name
= talloc_strdup(mem_ctx
, name
);
767 TALLOC_CHECK(obj
.data
.group
, ret
, done
);
769 obj
.data
.group
->xcounter
= 1;
770 /*obj.data.group->sec_desc*/
771 obj
.data
.group
->description
= "";
775 case GUMS_OBJ_DOMAIN
:
777 /* FIXME: should we check against global_sam_sid to make it impossible
778 to store more than one domain ? */
780 obj
.data
.domain
= (struct tdbsam2_domain_data
*)talloc_zero(mem_ctx
, sizeof(struct tdbsam2_domain_data
));
781 TALLOC_CHECK(obj
.data
.domain
, ret
, done
);
783 obj
.data
.domain
->dom_sid
= sid_dup_talloc(mem_ctx
, get_global_sam_sid());
784 TALLOC_CHECK(obj
.data
.domain
->dom_sid
, ret
, done
);
785 sid_copy(sid
, obj
.data
.domain
->dom_sid
);
787 obj
.data
.domain
->name
= talloc_strdup(mem_ctx
, name
);
788 TALLOC_CHECK(obj
.data
.domain
, ret
, done
);
790 obj
.data
.domain
->xcounter
= 1;
791 /*obj.data.domain->sec_desc*/
792 obj
.data
.domain
->next_rid
= 0x3e9;
793 obj
.data
.domain
->description
= "";
799 ret
= NT_STATUS_UNSUCCESSFUL
;
803 ret
= store_object(mem_ctx
, &obj
, True
);
806 talloc_destroy(mem_ctx
);
810 static NTSTATUS
tdbsam2_delete_object(const DOM_SID
*sid
)
813 struct tdbsam2_object obj
;
819 DEBUG(0, ("tdbsam2_delete_object: no NULL pointers are accepted here!\n"));
820 return NT_STATUS_INVALID_PARAMETER
;
823 mem_ctx
= talloc_init("tdbsam2_delete_object");
825 DEBUG(0, ("tdbsam2_delete_object: Out of memory!\n"));
826 return NT_STATUS_NO_MEMORY
;
829 if (tdbsam2_db
== NULL
) {
830 if (NT_STATUS_IS_ERR(ret
= opentdb())) {
835 slprintf(keystr
, sizeof(keystr
)-1, "%s%s", SIDPREFIX
, sid_string_static(sid
));
837 key
.dsize
= strlen(keystr
) + 1;
839 data
= tdb_fetch(tdbsam2_db
, key
);
841 DEBUG(5, ("tdbsam2_delete_object: Error fetching database, SID entry not found!\n"));
842 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam2_db
)));
843 DEBUGADD(5, (" Key: %s\n", keystr
));
844 ret
= NT_STATUS_UNSUCCESSFUL
;
848 if (tdb_delete(tdbsam2_db
, key
) != TDB_SUCCESS
) {
849 DEBUG(5, ("tdbsam2_delete_object: Error deleting object!\n"));
850 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam2_db
)));
851 DEBUGADD(5, (" Key: %s\n", keystr
));
852 ret
= NT_STATUS_UNSUCCESSFUL
;
856 if (NT_STATUS_IS_ERR(init_tdbsam2_object_from_buffer(&obj
, mem_ctx
, data
.dptr
, data
.dsize
))) {
857 SAFE_FREE(data
.dptr
);
858 DEBUG(0, ("tdbsam2_delete_object: Error fetching database, malformed entry!\n"));
859 ret
= NT_STATUS_UNSUCCESSFUL
;
864 case GUMS_OBJ_DOMAIN
:
865 /* TODO: SHOULD WE ALLOW TO DELETE DOMAINS ? */
866 slprintf(keystr
, sizeof(keystr
) - 1, "%s%s", NAMEPREFIX
, obj
.data
.domain
->name
);
870 slprintf(keystr
, sizeof(keystr
) - 1, "%s%s", NAMEPREFIX
, obj
.data
.group
->name
);
872 case GUMS_OBJ_NORMAL_USER
:
873 slprintf(keystr
, sizeof(keystr
) - 1, "%s%s", NAMEPREFIX
, obj
.data
.user
->name
);
876 ret
= NT_STATUS_UNSUCCESSFUL
;
881 key
.dsize
= strlen(keystr
) + 1;
883 if (tdb_delete(tdbsam2_db
, key
) != TDB_SUCCESS
) {
884 DEBUG(5, ("tdbsam2_delete_object: Error deleting object!\n"));
885 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam2_db
)));
886 DEBUGADD(5, (" Key: %s\n", keystr
));
887 ret
= NT_STATUS_UNSUCCESSFUL
;
891 /* TODO: update the general database counter */
894 SAFE_FREE(data
.dptr
);
895 talloc_destroy(mem_ctx
);
899 static NTSTATUS
tdbsam2_get_object_from_sid(GUMS_OBJECT
**object
, const DOM_SID
*sid
, const int obj_type
)
902 struct tdbsam2_object obj
;
905 if (!object
|| !sid
) {
906 DEBUG(0, ("tdbsam2_get_object_from_sid: no NULL pointers are accepted here!\n"));
907 return NT_STATUS_INVALID_PARAMETER
;
910 mem_ctx
= talloc_init("tdbsam2_get_object_from_sid");
912 DEBUG(0, ("tdbsam2_get_object_from_sid: Out of memory!\n"));
913 return NT_STATUS_NO_MEMORY
;
916 ret
= get_object_by_sid(mem_ctx
, &obj
, sid
);
917 if (NT_STATUS_IS_ERR(ret
) || (obj_type
&& obj
.type
!= obj_type
)) {
918 DEBUG(0, ("tdbsam2_get_object_from_sid: error fetching object or wrong object type!\n"));
922 ret
= data_to_gums_object(object
, &obj
);
923 if (NT_STATUS_IS_ERR(ret
)) {
924 DEBUG(0, ("tdbsam2_get_object_from_sid: error setting object data!\n"));
929 talloc_destroy(mem_ctx
);
933 static NTSTATUS
tdbsam2_get_object_from_name(GUMS_OBJECT
**object
, const char *name
, const int obj_type
)
936 struct tdbsam2_object obj
;
939 if (!object
|| !name
) {
940 DEBUG(0, ("tdbsam2_get_object_from_sid: no NULL pointers are accepted here!\n"));
941 return NT_STATUS_INVALID_PARAMETER
;
944 mem_ctx
= talloc_init("tdbsam2_get_object_from_sid");
946 DEBUG(0, ("tdbsam2_get_object_from_sid: Out of memory!\n"));
947 return NT_STATUS_NO_MEMORY
;
950 ret
= get_object_by_name(mem_ctx
, &obj
, name
);
951 if (NT_STATUS_IS_ERR(ret
) || (obj_type
&& obj
.type
!= obj_type
)) {
952 DEBUG(0, ("tdbsam2_get_object_from_sid: error fetching object or wrong object type!\n"));
956 ret
= data_to_gums_object(object
, &obj
);
957 if (NT_STATUS_IS_ERR(ret
)) {
958 DEBUG(0, ("tdbsam2_get_object_from_sid: error setting object data!\n"));
963 talloc_destroy(mem_ctx
);
967 /* This function is used to get the list of all objects changed since base_time, it is
968 used to support PDC<->BDC synchronization */
969 NTSTATUS (*get_updated_objects
) (GUMS_OBJECT
**objects
, const NTTIME base_time
);
971 static NTSTATUS
tdbsam2_enumerate_objects_start(void *handle
, const DOM_SID
*sid
, const int obj_type
)
973 struct tdbsam2_enum_objs
*teo
, *t
;
976 teo
= (struct tdbsam2_enum_objs
*)calloc(1, sizeof(struct tdbsam2_enum_objs
));
978 DEBUG(0, ("tdbsam2_enumerate_objects_start: Out of Memory!\n"));
979 return NT_STATUS_NO_MEMORY
;
982 teo
->type
= obj_type
;
984 sid_to_string(teo
->dom_sid
, sid
);
987 get_private_directory(tdbfile
);
988 pstrcat(tdbfile
, "/");
989 pstrcat(tdbfile
, TDB_FILE_NAME
);
991 teo
->db
= tdb_open_log(tdbfile
, 0, TDB_DEFAULT
, O_RDONLY
, 0600);
994 DEBUG(0, ("tdbsam2_enumerate_objects_start: Unable to open database (%s)!\n", tdbfile
));
996 return NT_STATUS_UNSUCCESSFUL
;
1000 *teo_handlers
= teo
;
1011 teo
->key
= tdb_firstkey(teo
->db
);
1013 return NT_STATUS_OK
;
1016 static NTSTATUS
tdbsam2_enumerate_objects_get_next(GUMS_OBJECT
**object
, void *handle
)
1019 TALLOC_CTX
*mem_ctx
;
1021 struct tdbsam2_enum_objs
*teo
;
1022 struct tdbsam2_object obj
;
1023 const char *prefix
= SIDPREFIX
;
1024 const int preflen
= strlen(prefix
);
1026 if (!object
|| !handle
) {
1027 DEBUG(0, ("tdbsam2_get_object_from_sid: no NULL pointers are accepted here!\n"));
1028 return NT_STATUS_INVALID_PARAMETER
;
1031 teo
= (struct tdbsam2_enum_objs
*)handle
;
1033 mem_ctx
= talloc_init("tdbsam2_enumerate_objects_get_next");
1035 DEBUG(0, ("tdbsam2_enumerate_objects_get_next: Out of memory!\n"));
1036 return NT_STATUS_NO_MEMORY
;
1039 while ((teo
->key
.dsize
!= 0)) {
1040 int len
, version
, type
, size
;
1043 if (strncmp(teo
->key
.dptr
, prefix
, preflen
)) {
1044 teo
->key
= tdb_nextkey(teo
->db
, teo
->key
);
1049 if (strncmp(&(teo
->key
.dptr
[preflen
]), teo
->dom_sid
, strlen(teo
->dom_sid
))) {
1050 teo
->key
= tdb_nextkey(teo
->db
, teo
->key
);
1055 data
= tdb_fetch(teo
->db
, teo
->key
);
1057 DEBUG(5, ("tdbsam2_enumerate_objects_get_next: Error fetching database, SID entry not found!\n"));
1058 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(teo
->db
)));
1059 DEBUGADD(5, (" Key: %s\n", teo
->key
.dptr
));
1060 ret
= NT_STATUS_UNSUCCESSFUL
;
1064 len
= tdb_unpack (data
.dptr
, data
.dsize
, TDB_FORMAT_STRING
,
1070 DEBUG(5, ("tdbsam2_enumerate_objects_get_next: Error unable to unpack data!\n"));
1071 ret
= NT_STATUS_UNSUCCESSFUL
;
1076 if (teo
->type
&& type
!= teo
->type
) {
1077 SAFE_FREE(data
.dptr
);
1079 teo
->key
= tdb_nextkey(teo
->db
, teo
->key
);
1086 if (data
.dsize
!= 0) {
1087 if (NT_STATUS_IS_ERR(init_tdbsam2_object_from_buffer(&obj
, mem_ctx
, data
.dptr
, data
.dsize
))) {
1088 SAFE_FREE(data
.dptr
);
1089 DEBUG(0, ("tdbsam2_enumerate_objects_get_next: Error fetching database, malformed entry!\n"));
1090 ret
= NT_STATUS_UNSUCCESSFUL
;
1093 SAFE_FREE(data
.dptr
);
1096 ret
= data_to_gums_object(object
, &obj
);
1099 talloc_destroy(mem_ctx
);
1103 static NTSTATUS
tdbsam2_enumerate_objects_stop(void *handle
)
1105 struct tdbsam2_enum_objs
*teo
, *t
, *p
;
1107 teo
= (struct tdbsam2_enum_objs
*)handle
;
1109 if (*teo_handlers
== teo
) {
1110 *teo_handlers
= teo
->next
;
1117 DEBUG(0, ("tdbsam2_enumerate_objects_stop: Error, handle not found!\n"));
1118 return NT_STATUS_UNSUCCESSFUL
;
1127 return NT_STATUS_OK
;
1130 /* This function MUST be used ONLY by PDC<->BDC replication code or recovery tools.
1131 Never use this function to update an object in the database, use set_object_values() */
1132 NTSTATUS (*set_object
) (const GUMS_OBJECT
*object
);
1134 /* set object values function */
1135 NTSTATUS (*set_object_values
) (DOM_SID
*sid
, uint32 count
, GUMS_DATA_SET
*data_set
);
1137 /* Group related functions */
1138 NTSTATUS (*add_memberss_to_group
) (const DOM_SID
*group
, const DOM_SID
**members
);
1139 NTSTATUS (*delete_members_from_group
) (const DOM_SID
*group
, const DOM_SID
**members
);
1140 NTSTATUS (*enumerate_group_members
) (DOM_SID
**members
, const DOM_SID
*sid
, const int type
);
1142 NTSTATUS (*get_sid_groups
) (DOM_SID
**groups
, const DOM_SID
*sid
);
1144 NTSTATUS (*lock_sid
) (const DOM_SID
*sid
);
1145 NTSTATUS (*unlock_sid
) (const DOM_SID
*sid
);
1147 /* privileges related functions */
1149 NTSTATUS (*add_members_to_privilege
) (const LUID_ATTR
*priv
, const DOM_SID
**members
);
1150 NTSTATUS (*delete_members_from_privilege
) (const LUID_ATTR
*priv
, const DOM_SID
**members
);
1151 NTSTATUS (*enumerate_privilege_members
) (DOM_SID
**members
, const LUID_ATTR
*priv
);
1152 NTSTATUS (*get_sid_privileges
) (DOM_SID
**privs
, const DOM_SID
*sid
);
1153 /* warning!: set_privilege will overwrite a prior existing privilege if such exist */
1154 NTSTATUS (*set_privilege
) (GUMS_PRIVILEGE
*priv
);
1157 int gumm_init(GUMS_FUNCTIONS
**storage
)
1166 int main(int argc
, char *argv
[])
1172 printf ("not enough arguments!\n");
1176 if (!lp_load(dyn_CONFIGFILE
,True
,False
,False
)) {
1177 fprintf(stderr
, "Can't load %s - run testparm to debug it\n", dyn_CONFIGFILE
);
1181 ret
= tdbsam2_new_object(&dsid
, "_domain_", GUMS_OBJ_DOMAIN
);
1182 if (NT_STATUS_IS_OK(ret
)) {
1183 printf ("_domain_ created, sid=%s\n", sid_string_static(&dsid
));
1185 printf ("_domain_ creation error n. 0x%08x\n", ret
.v
);
1187 ret
= tdbsam2_new_object(&dsid
, argv
[1], GUMS_OBJ_NORMAL_USER
);
1188 if (NT_STATUS_IS_OK(ret
)) {
1189 printf ("%s user created, sid=%s\n", argv
[1], sid_string_static(&dsid
));
1191 printf ("%s user creation error n. 0x%08x\n", argv
[1], ret
.v
);