Delete unused label to fix compiler warning.
[Samba.git] / source3 / sam / gumm_tdb.c
blob2623180afb5ecf180ca954f8c56701d130a0d06e
1 /*
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
9 *
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)
13 * any later version.
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
18 * more details.
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.
25 #include "includes.h"
26 #include "tdbsam2.h"
27 #include "tdbsam2_parse_info.h"
29 static int tdbgumm_debug_level = DBGC_ALL;
30 #undef DBGC_CLASS
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 {
45 uint32 type;
46 fstring 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;
58 struct tdbsam2_object {
59 uint32 type;
60 uint32 version;
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;
72 int iret;
73 char *obj_data;
74 int data_size = 0;
75 int len;
77 len = tdb_unpack (buffer, size, TDB_FORMAT_STRING,
78 &(object->version),
79 &(object->type),
80 &data_size, &obj_data);
82 if (len == -1)
83 goto done;
85 /* version is checked inside this function so that backward compatibility code can be
86 called eventually.
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"));
90 goto done;
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) {
98 case GUMS_OBJ_DOMAIN:
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);
104 break;
105 case GUMS_OBJ_GROUP:
106 case GUMS_OBJ_ALIAS:
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);
112 break;
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);
119 break;
120 default:
121 DEBUG(3,("init_tdbsam2_object_from_buffer: Error, wrong object type number!\n"));
122 goto done;
125 if (iret != 0) {
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 ?"));
128 goto done;
131 ret = NT_STATUS_OK;
132 done:
133 SAFE_FREE(obj_data);
134 return ret;
137 static NTSTATUS init_buffer_from_tdbsam2_object(char **buffer, size_t *len, TALLOC_CTX *mem_ctx, struct tdbsam2_object *object)
140 NTSTATUS ret;
141 char *buf1 = NULL;
142 size_t buflen;
144 if (!buffer)
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);
150 break;
151 case GUMS_OBJ_GROUP:
152 case GUMS_OBJ_ALIAS:
153 buf1 = gen_dump(mem_ctx, pinfo_tdbsam2_group_data, (char *)(object->data.group), 0);
154 break;
155 case GUMS_OBJ_NORMAL_USER:
156 buf1 = gen_dump(mem_ctx, pinfo_tdbsam2_user_data, (char *)(object->data.user), 0);
157 break;
158 default:
159 DEBUG(3,("init_buffer_from_tdbsam2_object: Error, wrong object type number!\n"));
160 return NT_STATUS_UNSUCCESSFUL;
163 if (buf1 == NULL) {
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,
169 TDBSAM_VERSION,
170 object->type,
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,
177 TDBSAM_VERSION,
178 object->type,
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",
183 buflen, *len));
184 *buffer = NULL;
185 ret = NT_STATUS_UNSUCCESSFUL;
186 goto done;
189 ret = NT_STATUS_OK;
190 done:
191 return ret;
194 static NTSTATUS opentdb(void)
196 if (!tdbsam2_db) {
197 pstring tdbfile;
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);
203 if (!tdbsam2_db)
205 DEBUG(0, ("opentdb: Unable to open database (%s)!\n", tdbfile));
206 return NT_STATUS_UNSUCCESSFUL;
210 return NT_STATUS_OK;
213 static NTSTATUS get_object_by_sid(TALLOC_CTX *mem_ctx, struct tdbsam2_object *obj, const DOM_SID *sid)
215 NTSTATUS ret;
216 TDB_DATA data, key;
217 fstring keystr;
219 if (!obj || !mem_ctx || !sid)
220 return NT_STATUS_INVALID_PARAMETER;
222 if (NT_STATUS_IS_ERR(ret = opentdb())) {
223 return ret;
226 slprintf(keystr, sizeof(keystr)-1, "%s%s", SIDPREFIX, sid_string_static(sid));
227 key.dptr = keystr;
228 key.dsize = strlen(keystr) + 1;
230 data = tdb_fetch(tdbsam2_db, key);
231 if (!data.dptr) {
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);
245 return NT_STATUS_OK;
249 static NTSTATUS get_object_by_name(TALLOC_CTX *mem_ctx, struct tdbsam2_object *obj, const char* name)
252 NTSTATUS ret;
253 TDB_DATA data, key;
254 fstring keystr;
255 fstring objname;
256 DOM_SID sid;
257 char *obj_sidstr;
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())) {
264 return ret;
267 fstrcpy(objname, name);
268 strlower(objname);
270 slprintf(keystr, sizeof(keystr)-1, "%s%s", NAMEPREFIX, objname);
271 key.dptr = keystr;
272 key.dsize = strlen(keystr) + 1;
274 data = tdb_fetch(tdbsam2_db, key);
275 if (!data.dptr) {
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,
283 &obj_version,
284 &obj_type,
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)
307 NTSTATUS ret;
308 TDB_DATA data, key, key2;
309 fstring keystr;
310 fstring namestr;
311 int flag, r;
313 if (NT_STATUS_IS_ERR(ret = opentdb())) {
314 return ret;
317 if (new_obj) {
318 flag = TDB_INSERT;
319 } else {
320 flag = TDB_MODIFY;
323 ret = init_buffer_from_tdbsam2_object(&(data.dptr), &(data.dsize), mem_ctx, object);
324 if (NT_STATUS_IS_ERR(ret))
325 return 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);
331 break;
332 case GUMS_OBJ_GROUP:
333 case GUMS_OBJ_ALIAS:
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);
336 break;
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);
340 break;
341 default:
342 return NT_STATUS_UNSUCCESSFUL;
345 key.dptr = keystr;
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;
356 key2.dptr = namestr;
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 */
369 return NT_STATUS_OK;
372 static NTSTATUS get_next_sid(TALLOC_CTX *mem_ctx, DOM_SID **sid)
374 NTSTATUS ret;
375 struct tdbsam2_object obj;
376 DOM_SID *dom_sid = get_global_sam_sid();
377 uint32 new_rid;
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;
384 goto 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;
397 goto 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;
407 goto error;
410 return NT_STATUS_OK;
412 error:
413 return ret;
416 static NTSTATUS user_data_to_gums_object(GUMS_OBJECT **object, struct tdbsam2_user_data *userdata)
418 NTSTATUS ret;
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);
463 if (userdata->hours)
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);
477 ret = NT_STATUS_OK;
478 return ret;
480 error:
481 talloc_destroy((*object)->mem_ctx);
482 *object = NULL;
483 return ret;
486 static NTSTATUS group_data_to_gums_object(GUMS_OBJECT **object, struct tdbsam2_group_data *groupdata)
488 NTSTATUS ret;
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);
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 domain_data_to_gums_object(GUMS_OBJECT **object, struct tdbsam2_domain_data *domdata)
519 NTSTATUS ret;
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);
535 ret = NT_STATUS_OK;
536 return ret;
538 error:
539 talloc_destroy((*object)->mem_ctx);
540 *object = NULL;
541 return ret;
544 static NTSTATUS data_to_gums_object(GUMS_OBJECT **object, struct tdbsam2_object *data)
547 NTSTATUS ret;
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;
552 goto done;
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"));
558 goto done;
561 switch (data->type) {
562 case GUMS_OBJ_DOMAIN:
563 ret = domain_data_to_gums_object(object, data->data.domain);
564 break;
566 case GUMS_OBJ_NORMAL_USER:
567 ret = user_data_to_gums_object(object, data->data.user);
568 break;
570 case GUMS_OBJ_GROUP:
571 case GUMS_OBJ_ALIAS:
572 ret = group_data_to_gums_object(object, data->data.group);
573 break;
575 default:
576 ret = NT_STATUS_UNSUCCESSFUL;
579 done:
580 return ret;
584 /* GUMM object functions */
586 static NTSTATUS tdbsam2_get_domain_sid(DOM_SID *sid, const char* name)
589 NTSTATUS ret;
590 struct tdbsam2_object obj;
591 TALLOC_CTX *mem_ctx;
592 fstring domname;
594 if (!sid || !name)
595 return NT_STATUS_INVALID_PARAMETER;
597 mem_ctx = talloc_init("tdbsam2_get_domain_sid");
598 if (!mem_ctx) {
599 DEBUG(0, ("tdbsam2_new_object: Out of memory!\n"));
600 return NT_STATUS_NO_MEMORY;
603 if (NT_STATUS_IS_ERR(ret = opentdb())) {
604 goto done;
607 fstrcpy(domname, name);
608 strlower(domname);
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"));
614 goto done;
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;
620 goto done;
623 sid_copy(sid, obj.data.domain->dom_sid);
625 ret = NT_STATUS_OK;
627 done:
628 talloc_destroy(mem_ctx);
629 return ret;
632 static NTSTATUS tdbsam2_set_domain_sid (const DOM_SID *sid, const char *name)
635 NTSTATUS ret;
636 struct tdbsam2_object obj;
637 TALLOC_CTX *mem_ctx;
638 fstring domname;
640 if (!sid || !name)
641 return NT_STATUS_INVALID_PARAMETER;
643 mem_ctx = talloc_init("tdbsam2_set_domain_sid");
644 if (!mem_ctx) {
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())) {
651 goto done;
655 fstrcpy(domname, name);
656 strlower(domname);
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"));
664 goto done;
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;
670 goto done;
673 sid_copy(obj.data.domain->dom_sid, sid);
675 ret = store_object(mem_ctx, &obj, False);
677 done:
678 /* TODO: unlock here */
679 if (mem_ctx) talloc_destroy(mem_ctx);
680 return ret;
683 /* TODO */
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)
692 NTSTATUS ret;
693 struct tdbsam2_object obj;
694 TALLOC_CTX *mem_ctx;
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};
699 if (!sid || !name) {
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");
705 if (!mem_ctx) {
706 DEBUG(0, ("tdbsam2_new_object: Out of memory!\n"));
707 return NT_STATUS_NO_MEMORY;
710 obj.type = obj_type;
711 obj.version = TDBSAM_VERSION;
713 switch (obj_type) {
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;
755 break;
757 case GUMS_OBJ_GROUP:
758 case GUMS_OBJ_ALIAS:
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 = "";
773 break;
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 = "";
795 ret = NT_STATUS_OK;
796 break;
798 default:
799 ret = NT_STATUS_UNSUCCESSFUL;
800 goto done;
803 ret = store_object(mem_ctx, &obj, True);
805 done:
806 talloc_destroy(mem_ctx);
807 return ret;
810 static NTSTATUS tdbsam2_delete_object(const DOM_SID *sid)
812 NTSTATUS ret;
813 struct tdbsam2_object obj;
814 TALLOC_CTX *mem_ctx;
815 TDB_DATA data, key;
816 fstring keystr;
818 if (!sid) {
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");
824 if (!mem_ctx) {
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())) {
831 goto done;
835 slprintf(keystr, sizeof(keystr)-1, "%s%s", SIDPREFIX, sid_string_static(sid));
836 key.dptr = keystr;
837 key.dsize = strlen(keystr) + 1;
839 data = tdb_fetch(tdbsam2_db, key);
840 if (!data.dptr) {
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;
845 goto done;
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;
853 goto done;
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;
860 goto done;
863 switch (obj.type) {
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);
867 break;
868 case GUMS_OBJ_GROUP:
869 case GUMS_OBJ_ALIAS:
870 slprintf(keystr, sizeof(keystr) - 1, "%s%s", NAMEPREFIX, obj.data.group->name);
871 break;
872 case GUMS_OBJ_NORMAL_USER:
873 slprintf(keystr, sizeof(keystr) - 1, "%s%s", NAMEPREFIX, obj.data.user->name);
874 break;
875 default:
876 ret = NT_STATUS_UNSUCCESSFUL;
877 goto done;
880 key.dptr = keystr;
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;
888 goto done;
891 /* TODO: update the general database counter */
893 done:
894 SAFE_FREE(data.dptr);
895 talloc_destroy(mem_ctx);
896 return ret;
899 static NTSTATUS tdbsam2_get_object_from_sid(GUMS_OBJECT **object, const DOM_SID *sid, const int obj_type)
901 NTSTATUS ret;
902 struct tdbsam2_object obj;
903 TALLOC_CTX *mem_ctx;
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");
911 if (!mem_ctx) {
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"));
919 goto done;
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"));
925 goto done;
928 done:
929 talloc_destroy(mem_ctx);
930 return ret;
933 static NTSTATUS tdbsam2_get_object_from_name(GUMS_OBJECT **object, const char *name, const int obj_type)
935 NTSTATUS ret;
936 struct tdbsam2_object obj;
937 TALLOC_CTX *mem_ctx;
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");
945 if (!mem_ctx) {
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"));
953 goto done;
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"));
959 goto done;
962 done:
963 talloc_destroy(mem_ctx);
964 return ret;
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;
974 pstring tdbfile;
976 teo = (struct tdbsam2_enum_objs *)calloc(1, sizeof(struct tdbsam2_enum_objs));
977 if (!teo) {
978 DEBUG(0, ("tdbsam2_enumerate_objects_start: Out of Memory!\n"));
979 return NT_STATUS_NO_MEMORY;
982 teo->type = obj_type;
983 if (sid) {
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);
992 if (!teo->db)
994 DEBUG(0, ("tdbsam2_enumerate_objects_start: Unable to open database (%s)!\n", tdbfile));
995 SAFE_FREE(teo);
996 return NT_STATUS_UNSUCCESSFUL;
999 if (!teo_handlers) {
1000 *teo_handlers = teo;
1001 } else {
1002 t = *teo_handlers;
1003 while (t->next) {
1004 t = t->next;
1006 t->next = teo;
1009 handle = 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)
1018 NTSTATUS ret;
1019 TALLOC_CTX *mem_ctx;
1020 TDB_DATA data;
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");
1034 if (!mem_ctx) {
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;
1041 char *ptr;
1043 if (strncmp(teo->key.dptr, prefix, preflen)) {
1044 teo->key = tdb_nextkey(teo->db, teo->key);
1045 continue;
1048 if (teo->dom_sid) {
1049 if (strncmp(&(teo->key.dptr[preflen]), teo->dom_sid, strlen(teo->dom_sid))) {
1050 teo->key = tdb_nextkey(teo->db, teo->key);
1051 continue;
1055 data = tdb_fetch(teo->db, teo->key);
1056 if (!data.dptr) {
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;
1061 goto done;
1064 len = tdb_unpack (data.dptr, data.dsize, TDB_FORMAT_STRING,
1065 &version,
1066 &type,
1067 &size, &ptr);
1069 if (len == -1) {
1070 DEBUG(5, ("tdbsam2_enumerate_objects_get_next: Error unable to unpack data!\n"));
1071 ret = NT_STATUS_UNSUCCESSFUL;
1072 goto done;
1074 SAFE_FREE(ptr);
1076 if (teo->type && type != teo->type) {
1077 SAFE_FREE(data.dptr);
1078 data.dsize = 0;
1079 teo->key = tdb_nextkey(teo->db, teo->key);
1080 continue;
1083 break;
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;
1091 goto done;
1093 SAFE_FREE(data.dptr);
1096 ret = data_to_gums_object(object, &obj);
1098 done:
1099 talloc_destroy(mem_ctx);
1100 return ret;
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;
1111 } else {
1112 t = *teo_handlers;
1113 while (t != teo) {
1114 p = t;
1115 t = t->next;
1116 if (t == NULL) {
1117 DEBUG(0, ("tdbsam2_enumerate_objects_stop: Error, handle not found!\n"));
1118 return NT_STATUS_UNSUCCESSFUL;
1121 p = t->next;
1124 tdb_close(teo->db);
1125 SAFE_FREE(teo);
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)
1159 tdbsam2_db = NULL;
1160 teo_handlers = 0;
1162 return 0;
1165 #if 0
1166 int main(int argc, char *argv[])
1168 NTSTATUS ret;
1169 DOM_SID dsid;
1171 if (argc < 2) {
1172 printf ("not enough arguments!\n");
1173 exit(0);
1176 if (!lp_load(dyn_CONFIGFILE,True,False,False)) {
1177 fprintf(stderr, "Can't load %s - run testparm to debug it\n", dyn_CONFIGFILE);
1178 exit(1);
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));
1184 } else {
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));
1190 } else {
1191 printf ("%s user creation error n. 0x%08x\n", argv[1], ret.v);
1194 exit(0);
1196 #endif