fix inverted check using krb5_kt_resolve() and HAVE_MEMORY_KEYTAB; bug 912
[Samba/gebeck_regimport.git] / source3 / sam / gums_tdbsam2.c
blob217cf6f34eb92d9df420017436e3c8fa1df9df43
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 #if 0
26 static int gums_tdbsam2_debug_class = DBGC_ALL;
27 #endif
29 #undef DBGC_CLASS
30 #define DBGC_CLASS gums_tdbsam2_debug_class
33 #define TDBSAM_VERSION 20021215
34 #define TDB_FILE_NAME "tdbsam2.tdb"
35 #define NAMEPREFIX "NAME_"
36 #define SIDPREFIX "SID_"
37 #define PRIVILEGEPREFIX "PRIV_"
39 #define TDB_FORMAT_STRING "ddB"
41 #define TALLOC_CHECK(ptr, err, label) do { if ((ptr) == NULL) { DEBUG(0, ("%s: Out of memory!\n", FUNCTION_MACRO)); err = NT_STATUS_NO_MEMORY; goto label; } } while(0)
42 #define SET_OR_FAIL(func, label) do { if (!NT_STATUS_IS_OK(func)) { DEBUG(0, ("%s: Setting gums object data failed!\n", FUNCTION_MACRO)); goto label; } } while(0)
46 struct tdbsam2_enum_objs {
47 uint32 type;
48 DOM_SID *dom_sid;
49 TDB_CONTEXT *db;
50 TDB_DATA key;
51 struct tdbsam2_enum_objs *next;
54 union tdbsam2_data {
55 struct tdbsam2_domain_data *domain;
56 struct tdbsam2_user_data *user;
57 struct tdbsam2_group_data *group;
58 struct tdbsam2_priv_data *priv;
61 struct tdbsam2_object {
62 uint32 type;
63 uint32 version;
64 union tdbsam2_data data;
67 struct tdbsam2_private_data {
69 const char *storage;
70 struct tdbsam2_enum_objs *teo_handlers;
73 static struct tdbsam2_private_data *ts2_privs;
76 static NTSTATUS init_object_from_buffer(GUMS_OBJECT **go, char *buffer, int size)
79 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
80 TALLOC_CTX *mem_ctx;
81 int iret;
82 char *obj_data = NULL;
83 int data_size = 0;
84 int version, type;
85 int len;
87 mem_ctx = talloc_init("init_object_from_buffer");
88 if (!mem_ctx) {
89 DEBUG(0, ("init_object_from_buffer: Out of memory!\n"));
90 return NT_STATUS_NO_MEMORY;
93 len = tdb_unpack (buffer, size, TDB_FORMAT_STRING,
94 &version,
95 &type,
96 &data_size, &obj_data);
98 if (len == -1 || data_size <= 0)
99 goto done;
101 /* version is checked inside this function so that backward compatibility code can be
102 called eventually.
103 this way we can easily handle database format upgrades */
104 if (version != TDBSAM_VERSION) {
105 DEBUG(3,("init_tdbsam2_object_from_buffer: Error, db object has wrong tdbsam version!\n"));
106 goto done;
109 /* be sure the string is terminated before trying to parse it */
110 if (obj_data[data_size - 1] != '\0')
111 obj_data[data_size - 1] = '\0';
113 *go = (GUMS_OBJECT *)talloc_zero(mem_ctx, sizeof(GUMS_OBJECT));
114 TALLOC_CHECK(*go, ret, done);
116 switch (type) {
118 case GUMS_OBJ_DOMAIN:
119 iret = gen_parse(mem_ctx, pinfo_tdbsam2_domain_data, (char *)(*go), obj_data);
120 break;
122 case GUMS_OBJ_GROUP:
123 case GUMS_OBJ_ALIAS:
124 iret = gen_parse(mem_ctx, pinfo_tdbsam2_group_data, (char *)(*go), obj_data);
125 break;
127 case GUMS_OBJ_NORMAL_USER:
128 iret = gen_parse(mem_ctx, pinfo_tdbsam2_user_data, (char *)(*go), obj_data);
129 break;
131 case GUMS_OBJ_PRIVILEGE:
132 iret = gen_parse(mem_ctx, pinfo_tdbsam2_priv_data, (char *)(*go), obj_data);
133 break;
135 default:
136 DEBUG(3,("init_object_from_buffer: Error, wrong object type number!\n"));
137 goto done;
140 if (iret != 0) {
141 DEBUG(0, ("init_object_from_buffer: Fatal Error! Unable to parse object!\n"));
142 DEBUG(0, ("init_object_from_buffer: DB Corrupt ?"));
143 goto done;
146 (*go)->mem_ctx = mem_ctx;
148 ret = NT_STATUS_OK;
149 done:
150 SAFE_FREE(obj_data);
151 return ret;
154 static NTSTATUS init_buffer_from_object(char **buffer, size_t *len, TALLOC_CTX *mem_ctx, GUMS_OBJECT *object)
157 NTSTATUS ret;
158 char *genbuf = NULL;
159 size_t buflen;
161 if (!buffer)
162 return NT_STATUS_INVALID_PARAMETER;
164 switch (gums_get_object_type(object)) {
166 case GUMS_OBJ_DOMAIN:
167 genbuf = gen_dump(mem_ctx, pinfo_tdbsam2_domain_data, (char *)object, 0);
168 break;
170 case GUMS_OBJ_GROUP:
171 case GUMS_OBJ_ALIAS:
172 genbuf = gen_dump(mem_ctx, pinfo_tdbsam2_group_data, (char *)object, 0);
173 break;
175 case GUMS_OBJ_NORMAL_USER:
176 genbuf = gen_dump(mem_ctx, pinfo_tdbsam2_user_data, (char *)object, 0);
177 break;
179 case GUMS_OBJ_PRIVILEGE:
180 genbuf = gen_dump(mem_ctx, pinfo_tdbsam2_priv_data, (char *)object, 0);
181 break;
183 default:
184 DEBUG(3,("init_buffer_from_object: Error, wrong object type number!\n"));
185 return NT_STATUS_UNSUCCESSFUL;
188 if (genbuf == NULL) {
189 DEBUG(0, ("init_buffer_from_object: Fatal Error! Unable to dump object!\n"));
190 return NT_STATUS_UNSUCCESSFUL;
193 buflen = tdb_pack(NULL, 0, TDB_FORMAT_STRING,
194 TDBSAM_VERSION,
195 object->type,
196 strlen(genbuf) + 1, genbuf);
198 *buffer = talloc(mem_ctx, buflen);
199 TALLOC_CHECK(*buffer, ret, done);
201 *len = tdb_pack(*buffer, buflen, TDB_FORMAT_STRING,
202 TDBSAM_VERSION,
203 object->type,
204 strlen(genbuf) + 1, genbuf);
206 if (*len != buflen) {
207 DEBUG(0, ("init_buffer_from_object: something odd is going on here: bufflen (%d) != len (%d) in tdb_pack operations!\n",
208 buflen, *len));
209 *buffer = NULL;
210 ret = NT_STATUS_UNSUCCESSFUL;
211 goto done;
214 ret = NT_STATUS_OK;
215 done:
216 return ret;
219 static NTSTATUS opentdb(TDB_CONTEXT **tdb, BOOL readonly)
221 if (!tdb)
222 return NT_STATUS_INVALID_PARAMETER;
224 *tdb = tdb_open_log(ts2_privs->storage, 0, TDB_DEFAULT, readonly?(O_RDONLY):(O_RDWR | O_CREAT), 0600);
225 if (!(*tdb))
227 DEBUG(0, ("opentdb: Unable to open database (%s)!\n", ts2_privs->storage));
228 return NT_STATUS_UNSUCCESSFUL;
231 return NT_STATUS_OK;
234 static NTSTATUS get_object_by_sid(TDB_CONTEXT *tdb, GUMS_OBJECT **obj, const DOM_SID *sid)
236 NTSTATUS ret;
237 TDB_DATA data, key;
238 fstring keystr;
240 if (!obj || !sid)
241 return NT_STATUS_INVALID_PARAMETER;
243 slprintf(keystr, sizeof(keystr)-1, "%s%s", SIDPREFIX, sid_string_static(sid));
244 key.dptr = keystr;
245 key.dsize = strlen(keystr) + 1;
247 data = tdb_fetch(tdb, key);
248 if (!data.dptr) {
249 DEBUG(5, ("get_object_by_sid: Entry not found!\n"));
250 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdb)));
251 DEBUGADD(5, (" Key: %s\n", keystr));
252 ret = NT_STATUS_NOT_FOUND;
253 goto done;
256 if (!NT_STATUS_IS_OK(init_object_from_buffer(obj, data.dptr, data.dsize))) {
257 DEBUG(0, ("get_object_by_sid: Error fetching database, malformed entry!\n"));
258 ret = NT_STATUS_UNSUCCESSFUL;
259 goto done;
262 ret = NT_STATUS_OK;
264 done:
265 SAFE_FREE(data.dptr);
266 return ret;
269 static NTSTATUS get_object_by_name(TDB_CONTEXT *tdb, GUMS_OBJECT **obj, const char* name)
272 NTSTATUS ret = NT_STATUS_OK;
273 TDB_DATA data, key;
274 fstring keystr;
275 fstring objname;
276 DOM_SID sid;
277 fstring sidstr;
278 int sidstr_len;
280 if (!obj || !name)
281 return NT_STATUS_INVALID_PARAMETER;
283 /* Data is stored in all lower-case */
284 fstrcpy(objname, name);
285 strlower_m(objname);
287 slprintf(keystr, sizeof(keystr)-1, "%s%s", NAMEPREFIX, objname);
288 key.dptr = keystr;
289 key.dsize = strlen(keystr) + 1;
291 data = tdb_fetch(tdb, key);
292 if (!data.dptr) {
293 DEBUG(5, ("get_object_by_name: Entry not found!\n"));
294 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdb)));
295 DEBUGADD(5, (" Key: %s\n", keystr));
296 ret = NT_STATUS_NOT_FOUND;
297 goto done;
300 fstrcpy(sidstr, data.dptr);
301 sidstr_len = data.dsize;
303 SAFE_FREE(data.dptr);
305 if (sidstr_len <= 0) {
306 DEBUG(5, ("get_object_by_name: Error unpacking database object!\n"));
307 ret = NT_STATUS_UNSUCCESSFUL;
308 goto done;
311 if (!string_to_sid(&sid, sidstr)) {
312 DEBUG(5, ("get_object_by_name: Error invalid sid string found in database object!\n"));
313 ret = NT_STATUS_UNSUCCESSFUL;
314 goto done;
317 done:
318 if (NT_STATUS_IS_OK(ret))
319 return get_object_by_sid(tdb, obj, &sid);
320 return ret;
323 /* store a tdbsam2_object
324 * flag: TDB_REPLACE or TDB_MODIFY or TDB_INSERT
327 static NTSTATUS store_object(TDB_CONTEXT *tdb, const GUMS_OBJECT *object, int flag)
330 NTSTATUS ret = NT_STATUS_OK;
331 TDB_DATA data, data2, key, key2;
332 TALLOC_CTX *mem_ctx;
333 fstring keystr;
334 fstring sidstr;
335 fstring namestr;
336 fstring objname;
337 int r;
339 /* TODO: on object renaming/replacing this function should
340 * check name->sid record and delete the old one
343 mem_ctx = talloc_init("store_object");
344 if (!mem_ctx) {
345 DEBUG(0, ("store_object: Out of memory!\n"));
346 return NT_STATUS_NO_MEMORY;
349 if (!NT_STATUS_IS_OK(ret = init_buffer_from_object(&(data.dptr), &(data.dsize), mem_ctx, object)))
350 goto done;
352 switch (object->type) {
354 case GUMS_OBJ_DOMAIN:
355 case GUMS_OBJ_GROUP:
356 case GUMS_OBJ_ALIAS:
357 case GUMS_OBJ_NORMAL_USER:
359 fstrcpy(sidstr, sid_string_static(gums_get_object_sid(object)));
360 slprintf(keystr, sizeof(keystr) - 1, "%s%s", SIDPREFIX, sidstr);
361 break;
363 default:
364 ret = NT_STATUS_UNSUCCESSFUL;
365 goto done;
368 /* Data is stored in all lower-case */
369 fstrcpy(objname, gums_get_object_name(object));
370 strlower_m(objname);
372 slprintf(namestr, sizeof(namestr) - 1, "%s%s", NAMEPREFIX, objname);
374 if (object->type != GUMS_OBJ_PRIVILEGE) {
375 key.dptr = keystr;
376 key.dsize = strlen(keystr) + 1;
378 if ((r = tdb_store(tdb, key, data, flag)) != TDB_SUCCESS) {
379 DEBUG(0, ("store_object: Unable to modify TDBSAM!\n"));
380 DEBUGADD(0, (" Error: %s", tdb_errorstr(tdb)));
381 DEBUGADD(0, (" occured while storing sid record (%s)\n", keystr));
382 if (r == TDB_ERR_EXISTS)
383 ret = NT_STATUS_UNSUCCESSFUL;
384 else
385 ret = NT_STATUS_INTERNAL_DB_ERROR;
386 goto done;
389 data2.dptr = sidstr;
390 data2.dsize = strlen(sidstr) + 1;
391 key2.dptr = namestr;
392 key2.dsize = strlen(namestr) + 1;
394 if ((r = tdb_store(tdb, key2, data2, flag)) != TDB_SUCCESS) {
395 DEBUG(0, ("store_object: Unable to modify TDBSAM!\n"));
396 DEBUGADD(0, (" Error: %s", tdb_errorstr(tdb)));
397 DEBUGADD(0, (" occured while storing name record (%s)\n", keystr));
398 DEBUGADD(0, (" attempting rollback operation.\n"));
399 if ((tdb_delete(tdb, key)) != TDB_SUCCESS) {
400 DEBUG(0, ("store_object: Unable to rollback! Check database consitency!\n"));
402 if (r == TDB_ERR_EXISTS)
403 ret = NT_STATUS_UNSUCCESSFUL;
404 else
405 ret = NT_STATUS_INTERNAL_DB_ERROR;
406 goto done;
408 } else {
409 key.dptr = namestr;
410 key.dsize = strlen(keystr) + 1;
412 if ((r = tdb_store(tdb, key, data, flag)) != TDB_SUCCESS) {
413 DEBUG(0, ("store_object: Unable to modify TDBSAM!\n"));
414 DEBUGADD(0, (" Error: %s", tdb_errorstr(tdb)));
415 DEBUGADD(0, (" occured while storing sid record (%s)\n", keystr));
416 if (r == TDB_ERR_EXISTS)
417 ret = NT_STATUS_UNSUCCESSFUL;
418 else
419 ret = NT_STATUS_INTERNAL_DB_ERROR;
420 goto done;
424 /* TODO: update the general database counter */
425 /* TODO: update this entry counter too */
427 done:
428 talloc_destroy(mem_ctx);
429 return ret;
432 #if 0
433 static NTSTATUS user_data_to_gums_object(GUMS_OBJECT **object, struct tdbsam2_user_data *userdata)
435 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
436 DATA_BLOB pwd;
438 if (!object || !userdata) {
439 DEBUG(0, ("tdbsam2_user_data_to_gums_object: no NULL pointers are accepted here!\n"));
440 return ret;
443 /* userdata->xcounter */
444 /* userdata->sec_desc */
446 SET_OR_FAIL(gums_set_object_sid(*object, userdata->user_sid), error);
447 SET_OR_FAIL(gums_set_object_name(*object, userdata->name), error);
449 SET_OR_FAIL(gums_set_user_pri_group(*object, userdata->group_sid), error);
451 if (userdata->description)
452 SET_OR_FAIL(gums_set_object_description(*object, userdata->description), error);
454 if (userdata->full_name)
455 SET_OR_FAIL(gums_set_user_fullname(*object, userdata->full_name), error);
457 if (userdata->home_dir)
458 SET_OR_FAIL(gums_set_user_homedir(*object, userdata->home_dir), error);
460 if (userdata->dir_drive)
461 SET_OR_FAIL(gums_set_user_dir_drive(*object, userdata->dir_drive), error);
463 if (userdata->logon_script)
464 SET_OR_FAIL(gums_set_user_logon_script(*object, userdata->logon_script), error);
466 if (userdata->profile_path)
467 SET_OR_FAIL(gums_set_user_profile_path(*object, userdata->profile_path), error);
469 if (userdata->workstations)
470 SET_OR_FAIL(gums_set_user_workstations(*object, userdata->workstations), error);
472 if (userdata->unknown_str)
473 SET_OR_FAIL(gums_set_user_unknown_str(*object, userdata->unknown_str), error);
475 if (userdata->munged_dial)
476 SET_OR_FAIL(gums_set_user_munged_dial(*object, userdata->munged_dial), error);
478 SET_OR_FAIL(gums_set_user_logon_divs(*object, userdata->logon_divs), error);
480 if (userdata->hours)
481 SET_OR_FAIL(gums_set_user_hours(*object, userdata->hours_len, userdata->hours), error);
483 SET_OR_FAIL(gums_set_user_unknown_3(*object, userdata->unknown_3), error);
484 SET_OR_FAIL(gums_set_user_unknown_5(*object, userdata->unknown_5), error);
485 SET_OR_FAIL(gums_set_user_unknown_6(*object, userdata->unknown_6), error);
487 SET_OR_FAIL(gums_set_user_logon_time(*object, *(userdata->logon_time)), error);
488 SET_OR_FAIL(gums_set_user_logoff_time(*object, *(userdata->logoff_time)), error);
489 SET_OR_FAIL(gums_set_user_kickoff_time(*object, *(userdata->kickoff_time)), error);
490 SET_OR_FAIL(gums_set_user_pass_last_set_time(*object, *(userdata->pass_last_set_time)), error);
491 SET_OR_FAIL(gums_set_user_pass_can_change_time(*object, *(userdata->pass_can_change_time)), error);
492 SET_OR_FAIL(gums_set_user_pass_must_change_time(*object, *(userdata->pass_must_change_time)), error);
494 pwd = data_blob(userdata->nt_pw_ptr, NT_HASH_LEN);
495 ret = gums_set_user_nt_pwd(*object, pwd);
496 data_blob_clear_free(&pwd);
497 if (!NT_STATUS_IS_OK(ret)) {
498 DEBUG(5, ("user_data_to_gums_object: failed to set nt password!\n"));
499 goto error;
501 pwd = data_blob(userdata->lm_pw_ptr, LM_HASH_LEN);
502 ret = gums_set_user_lm_pwd(*object, pwd);
503 data_blob_clear_free(&pwd);
504 if (!NT_STATUS_IS_OK(ret)) {
505 DEBUG(5, ("user_data_to_gums_object: failed to set lanman password!\n"));
506 goto error;
509 ret = NT_STATUS_OK;
510 return ret;
512 error:
513 talloc_destroy((*object)->mem_ctx);
514 *object = NULL;
515 return ret;
518 static NTSTATUS group_data_to_gums_object(GUMS_OBJECT **object, struct tdbsam2_group_data *groupdata)
520 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
522 if (!object || !groupdata) {
523 DEBUG(0, ("tdbsam2_group_data_to_gums_object: no NULL pointers are accepted here!\n"));
524 return ret;
527 /* groupdata->xcounter */
528 /* groupdata->sec_desc */
530 SET_OR_FAIL(gums_set_object_sid(*object, groupdata->group_sid), error);
531 SET_OR_FAIL(gums_set_object_name(*object, groupdata->name), error);
533 if (groupdata->description)
534 SET_OR_FAIL(gums_set_object_description(*object, groupdata->description), error);
536 if (groupdata->count)
537 SET_OR_FAIL(gums_set_group_members(*object, groupdata->count, groupdata->members), error);
539 ret = NT_STATUS_OK;
540 return ret;
542 error:
543 talloc_destroy((*object)->mem_ctx);
544 *object = NULL;
545 return ret;
548 static NTSTATUS domain_data_to_gums_object(GUMS_OBJECT **object, struct tdbsam2_domain_data *domdata)
551 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
553 if (!object || !*object || !domdata) {
554 DEBUG(0, ("tdbsam2_domain_data_to_gums_object: no NULL pointers are accepted here!\n"));
555 return NT_STATUS_INVALID_PARAMETER;
558 /* domdata->xcounter */
559 /* domdata->sec_desc */
561 SET_OR_FAIL(gums_set_object_sid(*object, domdata->dom_sid), error);
562 SET_OR_FAIL(gums_set_object_name(*object, domdata->name), error);
564 if (domdata->description)
565 SET_OR_FAIL(gums_set_object_description(*object, domdata->description), error);
567 ret = NT_STATUS_OK;
568 return ret;
570 error:
571 talloc_destroy((*object)->mem_ctx);
572 *object = NULL;
573 return ret;
576 static NTSTATUS priv_data_to_gums_object(GUMS_OBJECT **object, struct tdbsam2_priv_data *privdata)
579 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
581 if (!object || !*object || !privdata) {
582 DEBUG(0, ("tdbsam2_priv_data_to_gums_object: no NULL pointers are accepted here!\n"));
583 return ret;
586 /* domdata->xcounter */
587 /* domdata->sec_desc */
589 SET_OR_FAIL(gums_set_priv_luid_attr(*object, privdata->privilege), error);
590 SET_OR_FAIL(gums_set_object_name(*object, privdata->name), error);
592 if (privdata->description)
593 SET_OR_FAIL(gums_set_object_description(*object, privdata->description), error);
595 if (privdata->count)
596 SET_OR_FAIL(gums_set_priv_members(*object, privdata->count, privdata->members), error);
598 ret = NT_STATUS_OK;
599 return ret;
601 error:
602 talloc_destroy((*object)->mem_ctx);
603 *object = NULL;
604 return ret;
607 static NTSTATUS data_to_gums_object(GUMS_OBJECT **object, struct tdbsam2_object *data)
610 NTSTATUS ret;
612 if (!object || !data) {
613 DEBUG(0, ("tdbsam2_user_data_to_gums_object: no NULL structure pointers are accepted here!\n"));
614 ret = NT_STATUS_INVALID_PARAMETER;
615 goto done;
618 ret = gums_create_object(object, data->type);
619 if (!NT_STATUS_IS_OK(ret)) {
620 DEBUG(5, ("tdbsam2_user_data_to_gums_object: error creating gums object!\n"));
621 goto done;
624 switch (data->type) {
626 case GUMS_OBJ_DOMAIN:
627 ret = domain_data_to_gums_object(object, data->data.domain);
628 break;
630 case GUMS_OBJ_NORMAL_USER:
631 ret = user_data_to_gums_object(object, data->data.user);
632 break;
634 case GUMS_OBJ_GROUP:
635 case GUMS_OBJ_ALIAS:
636 ret = group_data_to_gums_object(object, data->data.group);
637 break;
639 case GUMS_OBJ_PRIVILEGE:
640 ret = priv_data_to_gums_object(object, data->data.priv);
641 break;
643 default:
644 ret = NT_STATUS_UNSUCCESSFUL;
647 done:
648 return ret;
650 #endif
652 /* GUMM object functions */
654 static NTSTATUS tdbsam2_get_domain_sid(DOM_SID *sid, const char* name)
657 NTSTATUS ret;
658 TDB_CONTEXT *tdb;
659 GUMS_OBJECT *go;
660 fstring domname;
662 if (!sid || !name)
663 return NT_STATUS_INVALID_PARAMETER;
665 if (!NT_STATUS_IS_OK(ret = opentdb(&tdb, True))) {
666 return ret;
669 /* Data is stored in all lower-case */
670 fstrcpy(domname, name);
671 strlower_m(domname);
673 if (!NT_STATUS_IS_OK(ret = get_object_by_name(tdb, &go, domname))) {
674 go = NULL;
675 DEBUG(0, ("tdbsam2_get_domain_sid: Error fetching database!\n"));
676 goto done;
679 if (gums_get_object_type(go) != GUMS_OBJ_DOMAIN) {
680 DEBUG(5, ("tdbsam2_get_domain_sid: Requested object is not a domain!\n"));
681 ret = NT_STATUS_OBJECT_TYPE_MISMATCH;
682 goto done;
685 sid_copy(sid, gums_get_object_sid(go));
687 ret = NT_STATUS_OK;
689 done:
690 if (go)
691 gums_destroy_object(&go);
692 tdb_close(tdb);
693 return ret;
696 static NTSTATUS get_next_sid(TDB_CONTEXT *tdb, DOM_SID *sid)
698 NTSTATUS ret;
699 GUMS_OBJECT *go;
700 DOM_SID dom_sid;
701 TDB_DATA dom_sid_key;
702 fstring dom_sid_str;
703 uint32 new_rid;
705 /* Find the domain SID */
706 if (!NT_STATUS_IS_OK(tdbsam2_get_domain_sid(&dom_sid, global_myname()))) {
707 DEBUG(0, ("get_next_sid: cannot found the domain sid!!\n"));
708 return NT_STATUS_UNSUCCESSFUL;
711 /* Lock the domain record */
712 sid_to_string(dom_sid_str, &dom_sid);
713 dom_sid_key.dptr = dom_sid_str;
714 dom_sid_key.dsize = strlen(dom_sid_key.dptr) + 1;
716 if(tdb_chainlock(tdb, dom_sid_key) != 0) {
717 DEBUG(0, ("get_next_sid: unable to lock domain record!\n"));
718 return NT_STATUS_UNSUCCESSFUL;
721 /* Get the domain object */
722 ret = get_object_by_sid(tdb, &go, &dom_sid);
723 if (!NT_STATUS_IS_OK(ret)) {
724 DEBUG(0, ("get_next_sid: unable to get root Domain object!\n"));
725 ret = NT_STATUS_INTERNAL_DB_ERROR;
726 goto done;
729 new_rid = gums_get_domain_next_rid(go);
731 /* Increment the RID Counter */
732 gums_set_domain_next_rid(go, new_rid+1);
734 /* Store back Domain object */
735 ret = store_object(tdb, go, TDB_MODIFY);
736 if (!NT_STATUS_IS_OK(ret)) {
737 DEBUG(0, ("get_next_sid: unable to update root Domain object!\n"));
738 ret = NT_STATUS_INTERNAL_DB_ERROR;
739 goto done;
742 /* Build the Domain SID to return */
743 sid_copy(sid, &dom_sid);
745 if (!sid_append_rid(sid, new_rid)) {
746 DEBUG(0, ("get_next_sid: unable to build new SID !?!\n"));
747 ret = NT_STATUS_UNSUCCESSFUL;
748 goto done;
751 ret = NT_STATUS_OK;
753 done:
754 /* Unlock the Domain object */
755 tdb_chainunlock(tdb, dom_sid_key);
757 return ret;
760 /* TODO */
761 NTSTATUS (*get_sequence_number) (void);
764 extern DOM_SID global_sid_NULL;
766 static NTSTATUS tdbsam2_new_object(DOM_SID *sid, const char *name, const int obj_type)
769 NTSTATUS ret = NT_STATUS_OK;
770 TDB_CONTEXT *tdb;
771 GUMS_OBJECT *go;
772 NTTIME null_time;
773 DATA_BLOB pw;
774 const char *defpw = "NOPASSWORDXXXXXX";
775 uint8 defhours[21] = {255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255};
777 if (!name) {
778 DEBUG(0, ("tdbsam2_new_object: no NULL pointers are accepted here!\n"));
779 return NT_STATUS_INVALID_PARAMETER;
782 if (!NT_STATUS_IS_OK(ret = opentdb(&tdb, False))) {
783 return ret;
786 if (!NT_STATUS_IS_OK(ret = gums_create_object(&go, obj_type))) {
787 go = NULL;
788 goto done;
791 if (obj_type != GUMS_OBJ_PRIVILEGE) {
792 if (!sid) {
793 ret = NT_STATUS_INVALID_PARAMETER;
794 goto done;
797 if (obj_type == GUMS_OBJ_DOMAIN) {
798 sid_copy(sid, get_global_sam_sid());
799 } else {
800 if (!NT_STATUS_IS_OK(ret = get_next_sid(tdb, sid)))
801 goto done;
804 gums_set_object_sid(go, sid);
807 gums_set_object_name(go, name);
808 gums_set_object_seq_num(go, 1);
810 /*obj.data.domain->sec_desc*/
812 switch (obj_type) {
813 case GUMS_OBJ_NORMAL_USER:
815 init_nt_time(&null_time);
817 gums_set_user_logon_time(go, null_time);
818 gums_set_user_logoff_time(go, null_time);
819 gums_set_user_kickoff_time(go, null_time);
820 gums_set_user_pass_last_set_time(go, null_time);
821 gums_set_user_pass_can_change_time(go, null_time);
822 gums_set_user_pass_must_change_time(go, null_time);
824 pw = data_blob(defpw, NT_HASH_LEN);
825 gums_set_user_nt_pwd(go, pw);
826 gums_set_user_lm_pwd(go, pw);
827 data_blob_free(&pw);
829 gums_set_user_logon_divs(go, 168);
830 gums_set_user_hours(go, 21, defhours);
832 gums_set_user_unknown_3(go, 0x00ffffff);
833 gums_set_user_bad_password_count(go, 0);
834 gums_set_user_logon_count(go, 0);
835 gums_set_user_unknown_6(go, 0x000004ec);
836 break;
838 case GUMS_OBJ_GROUP:
839 case GUMS_OBJ_ALIAS:
841 break;
843 case GUMS_OBJ_DOMAIN:
845 gums_set_domain_next_rid(go, 0x3e9);
847 break;
849 case GUMS_OBJ_PRIVILEGE:
851 break;
853 default:
854 ret = NT_STATUS_OBJECT_TYPE_MISMATCH;
855 goto done;
858 ret = store_object(tdb, go, TDB_INSERT);
860 done:
861 if (go)
862 gums_destroy_object(&go);
863 tdb_close(tdb);
864 return ret;
867 static NTSTATUS tdbsam2_delete_object(const DOM_SID *sid)
869 /* TODO: need to address privilege deletion */
870 NTSTATUS ret = NT_STATUS_OK;
871 TDB_CONTEXT *tdb;
872 GUMS_OBJECT *go;
873 TDB_DATA data, key;
874 fstring keystr;
876 if (!sid) {
877 DEBUG(0, ("tdbsam2_delete_object: no NULL pointers are accepted here!\n"));
878 return NT_STATUS_INVALID_PARAMETER;
881 if (!NT_STATUS_IS_OK(ret = opentdb(&tdb, False))) {
882 return ret;
885 slprintf(keystr, sizeof(keystr)-1, "%s%s", SIDPREFIX, sid_string_static(sid));
886 key.dptr = keystr;
887 key.dsize = strlen(keystr) + 1;
889 data = tdb_fetch(tdb, key);
890 if (!data.dptr) {
891 DEBUG(5, ("tdbsam2_delete_object: Error fetching database, SID entry not found!\n"));
892 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdb)));
893 DEBUGADD(5, (" Key: %s\n", keystr));
894 ret = NT_STATUS_UNSUCCESSFUL;
895 goto done;
898 if (tdb_delete(tdb, key) != TDB_SUCCESS) {
899 DEBUG(5, ("tdbsam2_delete_object: Error deleting object!\n"));
900 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdb)));
901 DEBUGADD(5, (" Key: %s\n", keystr));
902 ret = NT_STATUS_UNSUCCESSFUL;
903 goto done;
906 if (!NT_STATUS_IS_OK(init_object_from_buffer(&go, data.dptr, data.dsize))) {
907 DEBUG(0, ("tdbsam2_delete_object: Error fetching database, malformed entry!\n"));
908 ret = NT_STATUS_UNSUCCESSFUL;
909 goto done;
912 switch (go->type) {
913 case GUMS_OBJ_DOMAIN:
914 /* FIXME: SHOULD WE ALLOW TO DELETE DOMAINS ? */
915 case GUMS_OBJ_GROUP:
916 case GUMS_OBJ_ALIAS:
917 case GUMS_OBJ_NORMAL_USER:
918 slprintf(keystr, sizeof(keystr) - 1, "%s%s", NAMEPREFIX, gums_get_object_name(go));
919 break;
920 default:
921 ret = NT_STATUS_OBJECT_TYPE_MISMATCH;
922 goto done;
925 key.dptr = keystr;
926 key.dsize = strlen(keystr) + 1;
928 if (tdb_delete(tdb, key) != TDB_SUCCESS) {
929 DEBUG(5, ("tdbsam2_delete_object: Error deleting object!\n"));
930 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdb)));
931 DEBUGADD(5, (" Key: %s\n", keystr));
932 ret = NT_STATUS_UNSUCCESSFUL;
933 goto done;
936 /* TODO: update the general database counter */
938 done:
939 gums_destroy_object(&go);
940 SAFE_FREE(data.dptr);
941 return ret;
944 static NTSTATUS tdbsam2_get_object_from_sid(GUMS_OBJECT **object, const DOM_SID *sid, const int obj_type)
946 NTSTATUS ret;
947 TDB_CONTEXT *tdb;
949 if (!object || !sid) {
950 DEBUG(0, ("tdbsam2_get_object_from_sid: no NULL pointers are accepted here!\n"));
951 return NT_STATUS_INVALID_PARAMETER;
954 if (!NT_STATUS_IS_OK(ret = opentdb(&tdb, True))) {
955 return ret;
958 ret = get_object_by_sid(tdb, object, sid);
959 if (!NT_STATUS_IS_OK(ret) || (obj_type && gums_get_object_type(*object) != obj_type)) {
960 DEBUG(0, ("tdbsam2_get_object_from_sid: %s\n", nt_errstr(ret)));
961 goto error;
964 tdb_close(tdb);
965 return NT_STATUS_OK;
967 error:
968 gums_destroy_object(object);
969 tdb_close(tdb);
970 return ret;
973 static NTSTATUS tdbsam2_get_object_from_name(GUMS_OBJECT **object, const char *name, const int obj_type)
975 NTSTATUS ret;
976 TDB_CONTEXT *tdb;
978 if (!object || !name) {
979 DEBUG(0, ("tdbsam2_get_object_from_name: no NULL pointers are accepted here!\n"));
980 return NT_STATUS_INVALID_PARAMETER;
983 if (!NT_STATUS_IS_OK(ret = opentdb(&tdb, True))) {
984 return ret;
987 *object = NULL;
988 ret = get_object_by_name(tdb, object, name);
989 if (!NT_STATUS_IS_OK(ret) || (obj_type && gums_get_object_type(*object) != obj_type)) {
990 DEBUG(0, ("tdbsam2_get_object_from_name: %s\n", nt_errstr(ret)));
991 goto error;
994 tdb_close(tdb);
995 return NT_STATUS_OK;
997 error:
998 gums_destroy_object(object);
999 tdb_close(tdb);
1000 return ret;
1003 /* This function is used to get the list of all objects changed since base_time, it is
1004 used to support PDC<->BDC synchronization */
1005 NTSTATUS (*get_updated_objects) (GUMS_OBJECT **objects, const NTTIME base_time);
1007 static NTSTATUS tdbsam2_enumerate_objects_start(void **handle, const DOM_SID *sid, const int obj_type)
1009 struct tdbsam2_enum_objs *teo, *t;
1011 teo = (struct tdbsam2_enum_objs *)malloc(sizeof(struct tdbsam2_enum_objs));
1012 if (!teo) {
1013 DEBUG(0, ("tdbsam2_enumerate_objects_start: Out of Memory!\n"));
1014 return NT_STATUS_NO_MEMORY;
1016 memset(teo, 0, sizeof(struct tdbsam2_enum_objs));
1018 teo->type = obj_type;
1019 if (sid) {
1020 teo->dom_sid = (DOM_SID *)malloc(sizeof(DOM_SID));
1021 if (!teo->dom_sid) {
1022 DEBUG(0, ("tdbsam2_enumerate_objects_start: Out of Memory!\n"));
1023 return NT_STATUS_NO_MEMORY;
1025 sid_copy(teo->dom_sid, sid);
1028 if (!NT_STATUS_IS_OK(opentdb(&(teo->db), True)))
1030 DEBUG(0, ("tdbsam2_enumerate_objects_start: Unable to open database (%s)!\n", ts2_privs->storage));
1031 SAFE_FREE(teo);
1032 return NT_STATUS_UNSUCCESSFUL;
1035 if (!ts2_privs->teo_handlers) {
1036 ts2_privs->teo_handlers = teo;
1037 } else {
1038 t = ts2_privs->teo_handlers;
1039 while (t->next) {
1040 t = t->next;
1042 t->next = teo;
1045 *handle = teo;
1047 teo->key = tdb_firstkey(teo->db);
1049 return NT_STATUS_OK;
1052 static NTSTATUS tdbsam2_enumerate_objects_get_next(GUMS_OBJECT **object, void *handle)
1054 NTSTATUS ret;
1055 TDB_DATA data;
1056 struct tdbsam2_enum_objs *teo;
1057 const char *prefix = SIDPREFIX;
1058 const int preflen = strlen(prefix);
1059 fstring dom_sid_str;
1060 int dom_sid_str_len = 0;
1062 if (!object || !handle) {
1063 DEBUG(0, ("tdbsam2_get_object_from_sid: no NULL pointers are accepted here!\n"));
1064 return NT_STATUS_INVALID_PARAMETER;
1067 teo = (struct tdbsam2_enum_objs *)handle;
1069 if (teo->dom_sid) {
1070 sid_to_string(dom_sid_str, teo->dom_sid);
1071 dom_sid_str_len = strlen(dom_sid_str);
1074 while ((teo->key.dptr != NULL)) {
1075 int len, version, type, size;
1076 char *ptr;
1078 if (strncmp(teo->key.dptr, prefix, preflen)) {
1079 teo->key = tdb_nextkey(teo->db, teo->key);
1080 continue;
1083 if (dom_sid_str_len != 0) {
1084 if (strncmp(&(teo->key.dptr[preflen]), dom_sid_str, dom_sid_str_len)) {
1085 teo->key = tdb_nextkey(teo->db, teo->key);
1086 continue;
1090 data = tdb_fetch(teo->db, teo->key);
1091 if (!data.dptr) {
1092 DEBUG(5, ("tdbsam2_enumerate_objects_get_next: Error fetching database, SID entry not found!\n"));
1093 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(teo->db)));
1094 DEBUGADD(5, (" Key: %s\n", teo->key.dptr));
1095 ret = NT_STATUS_UNSUCCESSFUL;
1096 goto done;
1099 len = tdb_unpack (data.dptr, data.dsize, TDB_FORMAT_STRING,
1100 &version,
1101 &type,
1102 &size, &ptr);
1104 if (len == -1) {
1105 DEBUG(5, ("tdbsam2_enumerate_objects_get_next: Error unable to unpack data!\n"));
1106 ret = NT_STATUS_UNSUCCESSFUL;
1107 goto done;
1109 SAFE_FREE(ptr);
1111 if (teo->type && type != teo->type) {
1112 SAFE_FREE(data.dptr);
1113 data.dsize = 0;
1114 teo->key = tdb_nextkey(teo->db, teo->key);
1115 continue;
1118 break;
1121 if (teo->key.dptr == NULL) { /* no more objs */
1122 ret = NT_STATUS_NO_MORE_ENTRIES;
1123 goto done;
1126 if (!NT_STATUS_IS_OK(ret = init_object_from_buffer(object, data.dptr, data.dsize))) {
1127 SAFE_FREE(data.dptr);
1128 DEBUG(0, ("tdbsam2_enumerate_objects_get_next: Error fetching database, malformed entry!\n"));
1129 ret = NT_STATUS_UNSUCCESSFUL;
1130 goto done;
1132 SAFE_FREE(data.dptr);
1134 /* prepare next run */
1135 teo->key = tdb_nextkey(teo->db, teo->key);
1137 done:
1138 return ret;
1141 static NTSTATUS tdbsam2_enumerate_objects_stop(void *handle)
1143 struct tdbsam2_enum_objs *teo, *t, *p;
1145 teo = (struct tdbsam2_enum_objs *)handle;
1147 if (ts2_privs->teo_handlers == teo) {
1148 ts2_privs->teo_handlers = teo->next;
1149 } else {
1150 t = ts2_privs->teo_handlers;
1151 while (t != teo) {
1152 p = t;
1153 t = t->next;
1154 if (t == NULL) {
1155 DEBUG(0, ("tdbsam2_enumerate_objects_stop: Error, handle not found!\n"));
1156 return NT_STATUS_UNSUCCESSFUL;
1159 p = t->next;
1162 tdb_close(teo->db);
1163 SAFE_FREE(teo->dom_sid);
1164 SAFE_FREE(teo);
1166 return NT_STATUS_OK;
1169 static NTSTATUS tdbsam2_set_object(const GUMS_OBJECT *go)
1171 NTSTATUS ret;
1172 TDB_CONTEXT *tdb;
1174 if (!go)
1175 return NT_STATUS_INVALID_PARAMETER;
1177 if (!NT_STATUS_IS_OK(ret = opentdb(&tdb, False))) {
1178 return ret;
1181 ret = store_object(tdb, go, TDB_REPLACE);
1183 tdb_close(tdb);
1184 return ret;
1187 #if 0
1188 /* set object values function */
1189 static NTSTATUS (*set_object_values) (DOM_SID *sid, uint32 count, GUMS_DATA_SET *data_set);
1191 /* Group related functions */
1192 static NTSTATUS (*add_memberss_to_group) (const DOM_SID *group, const DOM_SID **members);
1193 NTSTATUS (*delete_members_from_group) (const DOM_SID *group, const DOM_SID **members);
1194 static NTSTATUS (*enumerate_group_members) (DOM_SID **members, const DOM_SID *sid, const int type);
1196 static NTSTATUS (*get_sid_groups) (DOM_SID **groups, const DOM_SID *sid);
1198 static NTSTATUS (*lock_sid) (const DOM_SID *sid);
1199 static NTSTATUS (*unlock_sid) (const DOM_SID *sid);
1201 /* privileges related functions */
1203 static NTSTATUS (*add_members_to_privilege) (const LUID_ATTR *priv, const DOM_SID **members);
1204 static NTSTATUS (*delete_members_from_privilege) (const LUID_ATTR *priv, const DOM_SID **members);
1205 static NTSTATUS (*enumerate_privilege_members) (DOM_SID **members, const LUID_ATTR *priv);
1206 static NTSTATUS (*get_sid_privileges) (DOM_SID **privs, const DOM_SID *sid);
1207 /* warning!: set_privilege will overwrite a prior existing privilege if such exist */
1208 static NTSTATUS (*set_privilege) (GUMS_PRIVILEGE *priv);
1209 #endif
1211 static void free_tdbsam2_private_data(void **vp)
1213 struct tdbsam2_private_data **tdb_privs = (struct tdbsam2_private_data **)vp;
1214 while (ts2_privs->teo_handlers)
1215 tdbsam2_enumerate_objects_stop(ts2_privs->teo_handlers);
1216 *tdb_privs = NULL;
1217 /* No need to free any further, as it is talloc()ed */
1220 static NTSTATUS init_tdbsam2(GUMS_FUNCTIONS *fns, const char *storage)
1222 NTSTATUS ret;
1223 TDB_CONTEXT *tdb;
1224 DOM_SID dom_sid;
1226 fns->name = talloc_strdup(fns->mem_ctx, "tdbsam2");
1228 fns->get_domain_sid = tdbsam2_get_domain_sid;
1229 /* fns->get_sequence_number = tdbsam2_get_sequence_number; */
1230 fns->new_object = tdbsam2_new_object;
1231 fns->delete_object = tdbsam2_delete_object;
1232 fns->get_object_from_sid = tdbsam2_get_object_from_sid;
1233 fns->get_object_from_name = tdbsam2_get_object_from_name;
1234 /* fns->get_updated_objects = tdbsam2_get_updated_objects; */
1235 fns->enumerate_objects_start = tdbsam2_enumerate_objects_start;
1236 fns->enumerate_objects_get_next = tdbsam2_enumerate_objects_get_next;
1237 fns->enumerate_objects_stop = tdbsam2_enumerate_objects_stop;
1238 fns->set_object = tdbsam2_set_object;
1239 /* fns->set_object_values = tdbsam2_set_object_values;
1240 fns->add_members_to_group = tdbsam2_add_members_to_group;
1241 fns->delete_members_from_group = tdbsam2_delete_members_from_group;
1242 fns->enumerate_group_members = tdbsam2_enumerate_group_members;
1243 fns->get_sid_groups = tdbsam2_get_sid_groups;
1244 fns->lock_sid = tdbsam2_lock_sid;
1245 fns->unlock_sid = tdbsam2_unlock_sid;
1246 fns->add_members_to_privilege = tdbsam2_add_members_to_privilege;
1247 fns->delete_members_from_privilege = tdbsam2_delete_members_from_privilege;
1248 fns->enumerate_privilege_members = tdbsam2_enumerate_privilege_members;
1249 fns->get_sid_privileges = tdbsam2_get_sid_privileges;
1250 fns->set_privilege = tdbsam2_set_privilege; */
1252 ts2_privs = talloc_zero(fns->mem_ctx, sizeof(struct tdbsam2_private_data));
1253 if (!ts2_privs) {
1254 DEBUG(0, ("talloc() failed for tdbsam2 private_data!\n"));
1255 return NT_STATUS_NO_MEMORY;
1258 if (storage) {
1259 ts2_privs->storage = talloc_strdup(fns->mem_ctx, storage);
1260 } else {
1261 pstring tdbfile;
1262 get_private_directory(tdbfile);
1263 pstrcat(tdbfile, "/");
1264 pstrcat(tdbfile, TDB_FILE_NAME);
1265 ts2_privs->storage = talloc_strdup(fns->mem_ctx, tdbfile);
1268 /* check tdb exist (or create it) */
1270 /* Find the domain SID */
1271 if (!NT_STATUS_IS_OK(tdbsam2_get_domain_sid(&dom_sid, global_myname()))) {
1272 /* db file does not exist or it is not inited */
1273 /* make the tdb file */
1274 if (!NT_STATUS_IS_OK(ret = opentdb(&tdb, False))) {
1275 return ret;
1277 tdb_close(tdb);
1279 if (!NT_STATUS_IS_OK(tdbsam2_get_domain_sid(&dom_sid, "BUILTIN"))) {
1280 gums_init_builtin_domain();
1283 gums_init_domain(get_global_sam_sid(), global_myname());
1286 fns->private_data = &ts2_privs;
1287 fns->free_private_data = free_tdbsam2_private_data;
1289 return NT_STATUS_OK;
1292 NTSTATUS gums_tdbsam2_init(void)
1295 if ((gums_tdbsam2_debug_class = debug_add_class("gums_tdbsam2")) == -1) {
1296 DEBUG(0, ("gums_tdbsam2: unable to register my own debug class! going on ...\n"));
1297 gums_tdbsam2_debug_class = DBGC_ALL;
1300 return gums_register_module(GUMS_INTERFACE_VERSION, "tdbsam2", init_tdbsam2);