First round of merging various UUID structures.
[Samba/gebeck_regimport.git] / source3 / sam / gums_tdbsam2.c
blob82e3923f7cd1eec2984e47951ded9932719f256b
1 /*
2 * Unix SMB/CIFS implementation.
3 * tdbsam2 - sam backend
4 * Copyright (C) Simo Sorce 2002-2003
5 *
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)
9 * any later version.
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
14 * more details.
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.
21 #include "includes.h"
22 #include "tdbsam2.h"
23 #include "tdbsam2_parse_info.h"
25 static int gums_tdbsam2_debug_class = DBGC_ALL;
27 #undef DBGC_CLASS
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 {
45 uint32 type;
46 DOM_SID *dom_sid;
47 TDB_CONTEXT *db;
48 TDB_DATA key;
49 struct tdbsam2_enum_objs *next;
52 union tdbsam2_data {
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 {
60 uint32 type;
61 uint32 version;
62 union tdbsam2_data data;
65 struct tdbsam2_private_data {
67 const char *storage;
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;
78 TALLOC_CTX *mem_ctx;
79 int iret;
80 char *obj_data = NULL;
81 int data_size = 0;
82 int version, type;
83 int len;
85 mem_ctx = talloc_init("init_object_from_buffer");
86 if (!mem_ctx) {
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,
92 &version,
93 &type,
94 &data_size, &obj_data);
96 if (len == -1 || data_size <= 0)
97 goto done;
99 /* version is checked inside this function so that backward compatibility code can be
100 called eventually.
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"));
104 goto done;
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);
114 switch (type) {
116 case GUMS_OBJ_DOMAIN:
117 iret = gen_parse(mem_ctx, pinfo_tdbsam2_domain_data, (char *)(*go), obj_data);
118 break;
120 case GUMS_OBJ_GROUP:
121 case GUMS_OBJ_ALIAS:
122 iret = gen_parse(mem_ctx, pinfo_tdbsam2_group_data, (char *)(*go), obj_data);
123 break;
125 case GUMS_OBJ_NORMAL_USER:
126 iret = gen_parse(mem_ctx, pinfo_tdbsam2_user_data, (char *)(*go), obj_data);
127 break;
129 case GUMS_OBJ_PRIVILEGE:
130 iret = gen_parse(mem_ctx, pinfo_tdbsam2_priv_data, (char *)(*go), obj_data);
131 break;
133 default:
134 DEBUG(3,("init_object_from_buffer: Error, wrong object type number!\n"));
135 goto done;
138 if (iret != 0) {
139 DEBUG(0, ("init_object_from_buffer: Fatal Error! Unable to parse object!\n"));
140 DEBUG(0, ("init_object_from_buffer: DB Corrupt ?"));
141 goto done;
144 (*go)->mem_ctx = mem_ctx;
146 ret = NT_STATUS_OK;
147 done:
148 SAFE_FREE(obj_data);
149 return ret;
152 static NTSTATUS init_buffer_from_object(char **buffer, size_t *len, TALLOC_CTX *mem_ctx, GUMS_OBJECT *object)
155 NTSTATUS ret;
156 char *genbuf = NULL;
157 size_t buflen;
159 if (!buffer)
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);
166 break;
168 case GUMS_OBJ_GROUP:
169 case GUMS_OBJ_ALIAS:
170 genbuf = gen_dump(mem_ctx, pinfo_tdbsam2_group_data, (char *)object, 0);
171 break;
173 case GUMS_OBJ_NORMAL_USER:
174 genbuf = gen_dump(mem_ctx, pinfo_tdbsam2_user_data, (char *)object, 0);
175 break;
177 case GUMS_OBJ_PRIVILEGE:
178 genbuf = gen_dump(mem_ctx, pinfo_tdbsam2_priv_data, (char *)object, 0);
179 break;
181 default:
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,
192 TDBSAM_VERSION,
193 object->type,
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,
200 TDBSAM_VERSION,
201 object->type,
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",
206 buflen, *len));
207 *buffer = NULL;
208 ret = NT_STATUS_UNSUCCESSFUL;
209 goto done;
212 ret = NT_STATUS_OK;
213 done:
214 return ret;
217 static NTSTATUS opentdb(TDB_CONTEXT **tdb, BOOL readonly)
219 if (!tdb)
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);
223 if (!(*tdb))
225 DEBUG(0, ("opentdb: Unable to open database (%s)!\n", ts2_privs->storage));
226 return NT_STATUS_UNSUCCESSFUL;
229 return NT_STATUS_OK;
232 static NTSTATUS get_object_by_sid(TDB_CONTEXT *tdb, GUMS_OBJECT **obj, const DOM_SID *sid)
234 NTSTATUS ret;
235 TDB_DATA data, key;
236 fstring keystr;
238 if (!obj || !sid)
239 return NT_STATUS_INVALID_PARAMETER;
241 slprintf(keystr, sizeof(keystr)-1, "%s%s", SIDPREFIX, sid_string_static(sid));
242 key.dptr = keystr;
243 key.dsize = strlen(keystr) + 1;
245 data = tdb_fetch(tdb, key);
246 if (!data.dptr) {
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;
251 goto done;
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;
257 goto done;
260 ret = NT_STATUS_OK;
262 done:
263 SAFE_FREE(data.dptr);
264 return ret;
267 static NTSTATUS get_object_by_name(TDB_CONTEXT *tdb, GUMS_OBJECT **obj, const char* name)
270 NTSTATUS ret = NT_STATUS_OK;
271 TDB_DATA data, key;
272 fstring keystr;
273 fstring objname;
274 DOM_SID sid;
275 fstring sidstr;
276 int sidstr_len;
278 if (!obj || !name)
279 return NT_STATUS_INVALID_PARAMETER;
281 /* Data is stored in all lower-case */
282 fstrcpy(objname, name);
283 strlower_m(objname);
285 slprintf(keystr, sizeof(keystr)-1, "%s%s", NAMEPREFIX, objname);
286 key.dptr = keystr;
287 key.dsize = strlen(keystr) + 1;
289 data = tdb_fetch(tdb, key);
290 if (!data.dptr) {
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;
295 goto done;
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;
306 goto done;
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;
312 goto done;
315 done:
316 if (NT_STATUS_IS_OK(ret))
317 return get_object_by_sid(tdb, obj, &sid);
318 return ret;
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;
330 TALLOC_CTX *mem_ctx;
331 fstring keystr;
332 fstring sidstr;
333 fstring namestr;
334 fstring objname;
335 int r;
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");
342 if (!mem_ctx) {
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)))
348 goto done;
350 switch (object->type) {
352 case GUMS_OBJ_DOMAIN:
353 case GUMS_OBJ_GROUP:
354 case GUMS_OBJ_ALIAS:
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);
359 break;
361 default:
362 ret = NT_STATUS_UNSUCCESSFUL;
363 goto done;
366 /* Data is stored in all lower-case */
367 fstrcpy(objname, gums_get_object_name(object));
368 strlower_m(objname);
370 slprintf(namestr, sizeof(namestr) - 1, "%s%s", NAMEPREFIX, objname);
372 if (object->type != GUMS_OBJ_PRIVILEGE) {
373 key.dptr = keystr;
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;
382 else
383 ret = NT_STATUS_INTERNAL_DB_ERROR;
384 goto done;
387 data2.dptr = sidstr;
388 data2.dsize = strlen(sidstr) + 1;
389 key2.dptr = namestr;
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;
402 else
403 ret = NT_STATUS_INTERNAL_DB_ERROR;
404 goto done;
406 } else {
407 key.dptr = namestr;
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;
416 else
417 ret = NT_STATUS_INTERNAL_DB_ERROR;
418 goto done;
422 /* TODO: update the general database counter */
423 /* TODO: update this entry counter too */
425 done:
426 talloc_destroy(mem_ctx);
427 return ret;
430 #if 0
431 static NTSTATUS user_data_to_gums_object(GUMS_OBJECT **object, struct tdbsam2_user_data *userdata)
433 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
434 DATA_BLOB pwd;
436 if (!object || !userdata) {
437 DEBUG(0, ("tdbsam2_user_data_to_gums_object: no NULL pointers are accepted here!\n"));
438 return ret;
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);
478 if (userdata->hours)
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"));
497 goto error;
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"));
504 goto error;
507 ret = NT_STATUS_OK;
508 return ret;
510 error:
511 talloc_destroy((*object)->mem_ctx);
512 *object = NULL;
513 return ret;
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"));
522 return ret;
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);
537 ret = NT_STATUS_OK;
538 return ret;
540 error:
541 talloc_destroy((*object)->mem_ctx);
542 *object = NULL;
543 return ret;
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);
565 ret = NT_STATUS_OK;
566 return ret;
568 error:
569 talloc_destroy((*object)->mem_ctx);
570 *object = NULL;
571 return ret;
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"));
581 return ret;
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);
593 if (privdata->count)
594 SET_OR_FAIL(gums_set_priv_members(*object, privdata->count, privdata->members), error);
596 ret = NT_STATUS_OK;
597 return ret;
599 error:
600 talloc_destroy((*object)->mem_ctx);
601 *object = NULL;
602 return ret;
605 static NTSTATUS data_to_gums_object(GUMS_OBJECT **object, struct tdbsam2_object *data)
608 NTSTATUS ret;
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;
613 goto done;
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"));
619 goto done;
622 switch (data->type) {
624 case GUMS_OBJ_DOMAIN:
625 ret = domain_data_to_gums_object(object, data->data.domain);
626 break;
628 case GUMS_OBJ_NORMAL_USER:
629 ret = user_data_to_gums_object(object, data->data.user);
630 break;
632 case GUMS_OBJ_GROUP:
633 case GUMS_OBJ_ALIAS:
634 ret = group_data_to_gums_object(object, data->data.group);
635 break;
637 case GUMS_OBJ_PRIVILEGE:
638 ret = priv_data_to_gums_object(object, data->data.priv);
639 break;
641 default:
642 ret = NT_STATUS_UNSUCCESSFUL;
645 done:
646 return ret;
648 #endif
650 /* GUMM object functions */
652 static NTSTATUS tdbsam2_get_domain_sid(DOM_SID *sid, const char* name)
655 NTSTATUS ret;
656 TDB_CONTEXT *tdb;
657 GUMS_OBJECT *go;
658 fstring domname;
660 if (!sid || !name)
661 return NT_STATUS_INVALID_PARAMETER;
663 if (!NT_STATUS_IS_OK(ret = opentdb(&tdb, True))) {
664 return ret;
667 /* Data is stored in all lower-case */
668 fstrcpy(domname, name);
669 strlower_m(domname);
671 if (!NT_STATUS_IS_OK(ret = get_object_by_name(tdb, &go, domname))) {
672 go = NULL;
673 DEBUG(0, ("tdbsam2_get_domain_sid: Error fetching database!\n"));
674 goto done;
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;
680 goto done;
683 sid_copy(sid, gums_get_object_sid(go));
685 ret = NT_STATUS_OK;
687 done:
688 if (go)
689 gums_destroy_object(&go);
690 tdb_close(tdb);
691 return ret;
694 static NTSTATUS get_next_sid(TDB_CONTEXT *tdb, DOM_SID *sid)
696 NTSTATUS ret;
697 GUMS_OBJECT *go;
698 DOM_SID dom_sid;
699 TDB_DATA dom_sid_key;
700 fstring dom_sid_str;
701 uint32 new_rid;
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;
724 goto done;
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;
737 goto done;
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;
746 goto done;
749 ret = NT_STATUS_OK;
751 done:
752 /* Unlock the Domain object */
753 tdb_chainunlock(tdb, dom_sid_key);
755 return ret;
758 /* TODO */
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;
768 TDB_CONTEXT *tdb;
769 GUMS_OBJECT *go;
770 NTTIME null_time;
771 DATA_BLOB pw;
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};
775 if (!name) {
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))) {
781 return ret;
784 if (!NT_STATUS_IS_OK(ret = gums_create_object(&go, obj_type))) {
785 go = NULL;
786 goto done;
789 if (obj_type != GUMS_OBJ_PRIVILEGE) {
790 if (!sid) {
791 ret = NT_STATUS_INVALID_PARAMETER;
792 goto done;
795 if (obj_type == GUMS_OBJ_DOMAIN) {
796 sid_copy(sid, get_global_sam_sid());
797 } else {
798 if (!NT_STATUS_IS_OK(ret = get_next_sid(tdb, sid)))
799 goto done;
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*/
810 switch (obj_type) {
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);
825 data_blob_free(&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);
834 break;
836 case GUMS_OBJ_GROUP:
837 case GUMS_OBJ_ALIAS:
839 break;
841 case GUMS_OBJ_DOMAIN:
843 gums_set_domain_next_rid(go, 0x3e9);
845 break;
847 case GUMS_OBJ_PRIVILEGE:
849 break;
851 default:
852 ret = NT_STATUS_OBJECT_TYPE_MISMATCH;
853 goto done;
856 ret = store_object(tdb, go, TDB_INSERT);
858 done:
859 if (go)
860 gums_destroy_object(&go);
861 tdb_close(tdb);
862 return ret;
865 static NTSTATUS tdbsam2_delete_object(const DOM_SID *sid)
867 /* TODO: need to address privilege deletion */
868 NTSTATUS ret = NT_STATUS_OK;
869 TDB_CONTEXT *tdb;
870 GUMS_OBJECT *go;
871 TDB_DATA data, key;
872 fstring keystr;
874 if (!sid) {
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))) {
880 return ret;
883 slprintf(keystr, sizeof(keystr)-1, "%s%s", SIDPREFIX, sid_string_static(sid));
884 key.dptr = keystr;
885 key.dsize = strlen(keystr) + 1;
887 data = tdb_fetch(tdb, key);
888 if (!data.dptr) {
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;
893 goto done;
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;
901 goto done;
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;
907 goto done;
910 switch (go->type) {
911 case GUMS_OBJ_DOMAIN:
912 /* FIXME: SHOULD WE ALLOW TO DELETE DOMAINS ? */
913 case GUMS_OBJ_GROUP:
914 case GUMS_OBJ_ALIAS:
915 case GUMS_OBJ_NORMAL_USER:
916 slprintf(keystr, sizeof(keystr) - 1, "%s%s", NAMEPREFIX, gums_get_object_name(go));
917 break;
918 default:
919 ret = NT_STATUS_OBJECT_TYPE_MISMATCH;
920 goto done;
923 key.dptr = keystr;
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;
931 goto done;
934 /* TODO: update the general database counter */
936 done:
937 gums_destroy_object(&go);
938 SAFE_FREE(data.dptr);
939 return ret;
942 static NTSTATUS tdbsam2_get_object_from_sid(GUMS_OBJECT **object, const DOM_SID *sid, const int obj_type)
944 NTSTATUS ret;
945 TDB_CONTEXT *tdb;
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))) {
953 return ret;
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)));
959 goto error;
962 tdb_close(tdb);
963 return NT_STATUS_OK;
965 error:
966 gums_destroy_object(object);
967 tdb_close(tdb);
968 return ret;
971 static NTSTATUS tdbsam2_get_object_from_name(GUMS_OBJECT **object, const char *name, const int obj_type)
973 NTSTATUS ret;
974 TDB_CONTEXT *tdb;
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))) {
982 return ret;
985 *object = NULL;
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)));
989 goto error;
992 tdb_close(tdb);
993 return NT_STATUS_OK;
995 error:
996 gums_destroy_object(object);
997 tdb_close(tdb);
998 return ret;
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));
1010 if (!teo) {
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;
1017 if (sid) {
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));
1029 SAFE_FREE(teo);
1030 return NT_STATUS_UNSUCCESSFUL;
1033 if (!ts2_privs->teo_handlers) {
1034 ts2_privs->teo_handlers = teo;
1035 } else {
1036 t = ts2_privs->teo_handlers;
1037 while (t->next) {
1038 t = t->next;
1040 t->next = teo;
1043 *handle = teo;
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)
1052 NTSTATUS ret;
1053 TDB_DATA data;
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;
1067 if (teo->dom_sid) {
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;
1074 char *ptr;
1076 if (strncmp(teo->key.dptr, prefix, preflen)) {
1077 teo->key = tdb_nextkey(teo->db, teo->key);
1078 continue;
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);
1084 continue;
1088 data = tdb_fetch(teo->db, teo->key);
1089 if (!data.dptr) {
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;
1094 goto done;
1097 len = tdb_unpack (data.dptr, data.dsize, TDB_FORMAT_STRING,
1098 &version,
1099 &type,
1100 &size, &ptr);
1102 if (len == -1) {
1103 DEBUG(5, ("tdbsam2_enumerate_objects_get_next: Error unable to unpack data!\n"));
1104 ret = NT_STATUS_UNSUCCESSFUL;
1105 goto done;
1107 SAFE_FREE(ptr);
1109 if (teo->type && type != teo->type) {
1110 SAFE_FREE(data.dptr);
1111 data.dsize = 0;
1112 teo->key = tdb_nextkey(teo->db, teo->key);
1113 continue;
1116 break;
1119 if (teo->key.dptr == NULL) { /* no more objs */
1120 ret = NT_STATUS_NO_MORE_ENTRIES;
1121 goto done;
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;
1128 goto done;
1130 SAFE_FREE(data.dptr);
1132 /* prepare next run */
1133 teo->key = tdb_nextkey(teo->db, teo->key);
1135 done:
1136 return ret;
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;
1147 } else {
1148 t = ts2_privs->teo_handlers;
1149 while (t != teo) {
1150 p = t;
1151 t = t->next;
1152 if (t == NULL) {
1153 DEBUG(0, ("tdbsam2_enumerate_objects_stop: Error, handle not found!\n"));
1154 return NT_STATUS_UNSUCCESSFUL;
1157 p = t->next;
1160 tdb_close(teo->db);
1161 SAFE_FREE(teo->dom_sid);
1162 SAFE_FREE(teo);
1164 return NT_STATUS_OK;
1167 static NTSTATUS tdbsam2_set_object(const GUMS_OBJECT *go)
1169 NTSTATUS ret;
1170 TDB_CONTEXT *tdb;
1172 if (!go)
1173 return NT_STATUS_INVALID_PARAMETER;
1175 if (!NT_STATUS_IS_OK(ret = opentdb(&tdb, False))) {
1176 return ret;
1179 ret = store_object(tdb, go, TDB_REPLACE);
1181 tdb_close(tdb);
1182 return ret;
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);
1212 *tdb_privs = NULL;
1213 /* No need to free any further, as it is talloc()ed */
1216 static NTSTATUS init_tdbsam2(GUMS_FUNCTIONS *fns, const char *storage)
1218 NTSTATUS ret;
1219 TDB_CONTEXT *tdb;
1220 DOM_SID dom_sid;
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));
1249 if (!ts2_privs) {
1250 DEBUG(0, ("talloc() failed for tdbsam2 private_data!\n"));
1251 return NT_STATUS_NO_MEMORY;
1254 if (storage) {
1255 ts2_privs->storage = talloc_strdup(fns->mem_ctx, storage);
1256 } else {
1257 pstring tdbfile;
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))) {
1271 return ret;
1273 tdb_close(tdb);
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);