import HEAD into svn+ssh://svn.samba.org/home/svn/samba/trunk
[metze/old/v3-2-winbind-ndr.git] / source / sam / gums_tdbsam2.c
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.
10  * 
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.
15  * 
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.
19  */
20
21 #include "includes.h"
22 #include "tdbsam2_parse_info.h"
23
24 #if 0
25 static int gums_tdbsam2_debug_class = DBGC_ALL;
26 #endif
27 /*
28 #undef DBGC_CLASS
29 #define DBGC_CLASS gums_tdbsam2_debug_class
30 */
31
32 #define TDBSAM_VERSION          20021215
33 #define TDB_FILE_NAME           "tdbsam2.tdb"
34 #define NAMEPREFIX              "NAME_"
35 #define SIDPREFIX               "SID_"
36 #define PRIVILEGEPREFIX         "PRIV_"
37
38 #define TDB_BASIC_OBJ_STRING    "ddd"
39 #define TDB_FORMAT_STRING       "dddB"
40 #define TDB_PRIV_FORMAT_STRING  "ddB"
41
42 #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)
43 #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
45
46
47 struct tdbsam2_enum_objs {
48         uint32 type;
49         DOM_SID *dom_sid;
50         TDB_CONTEXT *db;
51         TDB_DATA key;
52         struct tdbsam2_enum_objs *next;
53 };
54
55 struct tdbsam2_private_data {
56
57         const char *storage;
58         struct tdbsam2_enum_objs *teo_handlers;
59 };
60
61 static struct tdbsam2_private_data *ts2_privs;
62
63 static NTSTATUS init_object_from_buffer(GUMS_OBJECT **go, char *buffer, int size)
64 {
65
66         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
67         TALLOC_CTX *mem_ctx;
68         int iret;
69         char *obj_data = NULL;
70         int data_size = 0;
71         int version, type, seqnum;
72         int len;
73
74         mem_ctx = talloc_init("init_object_from_buffer");
75         if (!mem_ctx) {
76                 DEBUG(0, ("init_object_from_buffer: Out of memory!\n"));
77                 return NT_STATUS_NO_MEMORY;
78         }
79
80         len = tdb_unpack (buffer, size, TDB_FORMAT_STRING,
81                           &version,
82                           &type,
83                           &seqnum,
84                           &data_size, &obj_data);
85
86         if (len == -1 || data_size <= 0)
87                 goto done;
88
89         /* version is checked inside this function so that backward
90            compatibility code can be called eventually.
91            This way we can easily handle database format upgrades */
92         if (version != TDBSAM_VERSION) {
93                 DEBUG(3,("init_object_from_buffer: Error, db object has wrong tdbsam version!\n"));
94                 goto done;
95         }
96
97         /* be sure the string is terminated before trying to parse it */
98         if (obj_data[data_size - 1] != '\0')
99                 obj_data[data_size - 1] = '\0';
100
101         *go = (GUMS_OBJECT *)talloc_zero(mem_ctx, sizeof(GUMS_OBJECT));
102         TALLOC_CHECK(*go, ret, done);
103
104         switch (type) {
105
106                 case GUMS_OBJ_DOMAIN:
107                         iret = gen_parse(mem_ctx, pinfo_gums_domain, (char *)(*go), obj_data);
108                         break;
109
110                 case GUMS_OBJ_GROUP:
111                 case GUMS_OBJ_ALIAS:
112                         iret = gen_parse(mem_ctx, pinfo_gums_group, (char *)(*go), obj_data);
113                         break;
114
115                 case GUMS_OBJ_NORMAL_USER:
116                         iret = gen_parse(mem_ctx, pinfo_gums_user, (char *)(*go), obj_data);
117                         break;
118
119                 default:
120                         DEBUG(3,("init_object_from_buffer: Error, wrong object type number!\n"));
121                         goto done;
122         }
123
124         if (iret != 0) {
125                 DEBUG(0, ("init_object_from_buffer: Fatal Error! Unable to parse object!\n"));
126                 DEBUG(0, ("init_object_from_buffer: DB Corrupt ?"));
127                 goto done;
128         }
129
130         (*go)->mem_ctx = mem_ctx;
131
132         ret = NT_STATUS_OK;
133 done:
134         SAFE_FREE(obj_data);
135         return ret;
136 }
137
138 static NTSTATUS init_privilege_from_buffer(GUMS_PRIVILEGE **priv, char *buffer, int size)
139 {
140
141         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
142         TALLOC_CTX *mem_ctx;
143         int iret;
144         char *obj_data = NULL;
145         int data_size = 0;
146         int version, seqnum;
147         int len;
148
149         mem_ctx = talloc_init("init_privilege_from_buffer");
150         if (!mem_ctx) {
151                 DEBUG(0, ("init_privilege_from_buffer: Out of memory!\n"));
152                 return NT_STATUS_NO_MEMORY;
153         }
154
155         len = tdb_unpack (buffer, size, TDB_PRIV_FORMAT_STRING,
156                           &version,
157                           &seqnum,
158                           &data_size, &obj_data);
159
160         if (len == -1 || data_size <= 0)
161                 goto done;
162
163         /* version is checked inside this function so that backward
164            compatibility code can be called eventually.
165            This way we can easily handle database format upgrades */
166         if (version != TDBSAM_VERSION) {
167                 DEBUG(3,("init_privilege_from_buffer: Error, db object has wrong tdbsam version!\n"));
168                 goto done;
169         }
170
171         /* be sure the string is terminated before trying to parse it */
172         if (obj_data[data_size - 1] != '\0')
173                 obj_data[data_size - 1] = '\0';
174
175         *priv = (GUMS_PRIVILEGE *)talloc_zero(mem_ctx, sizeof(GUMS_PRIVILEGE));
176         TALLOC_CHECK(*priv, ret, done);
177
178         iret = gen_parse(mem_ctx, pinfo_gums_privilege, (char *)(*priv), obj_data);
179
180         if (iret != 0) {
181                 DEBUG(0, ("init_privilege_from_buffer: Fatal Error! Unable to parse object!\n"));
182                 DEBUG(0, ("init_privilege_from_buffer: DB Corrupt ?"));
183                 goto done;
184         }
185
186         (*priv)->mem_ctx = mem_ctx;
187
188         ret = NT_STATUS_OK;
189 done:
190         SAFE_FREE(obj_data);
191         return ret;
192 }
193
194 static NTSTATUS init_buffer_from_object(char **buffer, size_t *len, TALLOC_CTX *mem_ctx, GUMS_OBJECT *object)
195 {
196
197         NTSTATUS ret;
198         char *genbuf = NULL;
199         size_t buflen;
200
201         if (!buffer)
202                 return NT_STATUS_INVALID_PARAMETER;
203
204         switch (gums_get_object_type(object)) {
205
206                 case GUMS_OBJ_DOMAIN:
207                         genbuf = gen_dump(mem_ctx, pinfo_gums_domain, (char *)object, 0);
208                         break;
209
210                 case GUMS_OBJ_GROUP:
211                 case GUMS_OBJ_ALIAS:
212                         genbuf = gen_dump(mem_ctx, pinfo_gums_group, (char *)object, 0);
213                         break;
214
215                 case GUMS_OBJ_NORMAL_USER:
216                         genbuf = gen_dump(mem_ctx, pinfo_gums_user, (char *)object, 0);
217                         break;
218
219                 default:
220                         DEBUG(3,("init_buffer_from_object: Error, wrong object type number!\n"));
221                         return NT_STATUS_UNSUCCESSFUL;  
222         }
223         
224         if (genbuf == NULL) {
225                 DEBUG(0, ("init_buffer_from_object: Fatal Error! Unable to dump object!\n"));
226                 return NT_STATUS_UNSUCCESSFUL;
227         }
228
229         buflen = tdb_pack(NULL, 0,  TDB_FORMAT_STRING,
230                         TDBSAM_VERSION,
231                         object->type,
232                         object->seq_num,
233                         strlen(genbuf) + 1, genbuf);
234
235         *buffer = talloc(mem_ctx, buflen);
236         TALLOC_CHECK(*buffer, ret, done);
237
238         *len = tdb_pack(*buffer, buflen, TDB_FORMAT_STRING,
239                         TDBSAM_VERSION,
240                         object->type,
241                         object->seq_num,
242                         strlen(genbuf) + 1, genbuf);
243
244         if (*len != buflen) {
245                 DEBUG(0, ("init_buffer_from_object: something odd is going on here: bufflen (%d) != len (%d) in tdb_pack operations!\n", 
246                           buflen, *len));
247                 *buffer = NULL;
248                 ret = NT_STATUS_UNSUCCESSFUL;
249                 goto done;
250         }
251
252         ret = NT_STATUS_OK;
253 done:
254         return ret;
255 }
256
257 static NTSTATUS init_buffer_from_privilege(char **buffer, size_t *len, TALLOC_CTX *mem_ctx, GUMS_PRIVILEGE *priv)
258 {
259
260         NTSTATUS ret;
261         char *genbuf = NULL;
262         size_t buflen;
263
264         if (!buffer || !len || !mem_ctx || !priv)
265                 return NT_STATUS_INVALID_PARAMETER;
266
267         genbuf = gen_dump(mem_ctx, pinfo_gums_privilege, (char *)priv, 0);
268         
269         if (genbuf == NULL) {
270                 DEBUG(0, ("init_buffer_from_privilege: Fatal Error! Unable to dump object!\n"));
271                 return NT_STATUS_UNSUCCESSFUL;
272         }
273
274         buflen = tdb_pack(NULL, 0,  TDB_PRIV_FORMAT_STRING,
275                         TDBSAM_VERSION,
276                         priv->seq_num,
277                         strlen(genbuf) + 1, genbuf);
278
279         *buffer = talloc(mem_ctx, buflen);
280         TALLOC_CHECK(*buffer, ret, done);
281
282         *len = tdb_pack(*buffer, buflen, TDB_PRIV_FORMAT_STRING,
283                         TDBSAM_VERSION,
284                         priv->seq_num,
285                         strlen(genbuf) + 1, genbuf);
286
287         if (*len != buflen) {
288                 DEBUG(0, ("init_buffer_from_privilege: something odd is going on here: bufflen (%d) != len (%d) in tdb_pack operations!\n", 
289                           buflen, *len));
290                 *buffer = NULL;
291                 ret = NT_STATUS_UNSUCCESSFUL;
292                 goto done;
293         }
294
295         ret = NT_STATUS_OK;
296 done:
297         return ret;
298 }
299
300 static NTSTATUS opentdb(TDB_CONTEXT **tdb, BOOL readonly)
301 {
302         if (!tdb)
303                 return NT_STATUS_INVALID_PARAMETER;
304
305         *tdb = tdb_open_log(ts2_privs->storage, 0, TDB_DEFAULT, readonly?(O_RDONLY):(O_RDWR | O_CREAT), 0600);
306         if (!(*tdb))
307         {
308                 DEBUG(0, ("opentdb: Unable to open database (%s)!\n", ts2_privs->storage));
309                 return NT_STATUS_UNSUCCESSFUL;
310         }
311
312         return NT_STATUS_OK;
313 }
314
315 static NTSTATUS get_object_by_sid(TDB_CONTEXT *tdb, GUMS_OBJECT **obj, const DOM_SID *sid)
316 {
317         NTSTATUS ret;
318         TDB_DATA data, key;
319         fstring keystr;
320
321         if (!obj || !sid)
322                 return NT_STATUS_INVALID_PARAMETER;
323
324         slprintf(keystr, sizeof(keystr)-1, "%s%s", SIDPREFIX, sid_string_static(sid));
325         key.dptr = keystr;
326         key.dsize = strlen(keystr) + 1;
327
328         data = tdb_fetch(tdb, key);
329         if (!data.dptr) {
330                 DEBUG(5, ("get_object_by_sid: Entry not found!\n"));
331                 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdb)));
332                 DEBUGADD(5, (" Key: %s\n", keystr));
333                 ret = NT_STATUS_NOT_FOUND;
334                 goto done;
335         }
336
337         if (!NT_STATUS_IS_OK(init_object_from_buffer(obj, data.dptr, data.dsize))) {
338                 DEBUG(0, ("get_object_by_sid: Error fetching database, malformed entry!\n"));
339                 ret = NT_STATUS_UNSUCCESSFUL;
340                 goto done;
341         }
342
343         ret = NT_STATUS_OK;
344
345 done:
346         SAFE_FREE(data.dptr);
347         return ret;
348 }
349
350 static NTSTATUS make_full_object_name(TDB_CONTEXT *tdb, fstring objname, GUMS_OBJECT *object)
351 {
352         NTSTATUS ret;
353
354         objname[0] = '\0';
355
356         if (gums_get_object_type(object) == GUMS_OBJ_DOMAIN) {
357
358                 fstrcpy(objname, gums_get_object_name(object));
359
360         } else {
361                 GUMS_OBJECT *domain_object;
362                 DOM_SID domain_sid;
363                 uint32 *discard_rid;
364
365                 sid_copy(&domain_sid, gums_get_object_sid(object));
366                 sid_split_rid(&domain_sid, discard_rid);
367
368                 if (!NT_STATUS_IS_OK(get_object_by_sid(tdb,
369                                                         &domain_object,
370                                                         &domain_sid))) {
371
372                         DEBUG(3, ("Object's domain not found!\n"));
373                         ret = NT_STATUS_UNSUCCESSFUL;
374                         goto done;
375                 }
376
377                 fstrcpy(objname, gums_get_object_name(domain_object));
378                 fstrcat(objname, "\\");
379                 fstrcat(objname, gums_get_object_name(object));
380         }
381
382         ret = NT_STATUS_OK;
383
384 done:
385         return ret;
386 }
387
388 /* name should be in DOMAIN\NAME format */
389 static NTSTATUS get_object_by_name(TDB_CONTEXT *tdb, GUMS_OBJECT **obj, const char *fullname)
390 {
391
392         NTSTATUS ret = NT_STATUS_OK;
393         TDB_DATA data, key;
394         fstring keystr;
395         fstring objname;
396         DOM_SID sid;
397         fstring sidstr;
398         int sidstr_len;
399
400         if (!obj || !fullname)
401                 return NT_STATUS_INVALID_PARAMETER;
402
403         /* Data is stored in all lower-case */
404         fstrcpy(objname, fullname);
405         strlower_m(objname);
406
407         slprintf(keystr, sizeof(keystr)-1, "%s%s", NAMEPREFIX, objname);
408
409         key.dptr = keystr;
410         key.dsize = strlen(keystr) + 1;
411
412         data = tdb_fetch(tdb, key);
413         if (!data.dptr) {
414                 DEBUG(5, ("get_object_by_name: Entry not found!\n"));
415                 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdb)));
416                 DEBUGADD(5, (" Key: %s\n", keystr));
417                 ret = NT_STATUS_NOT_FOUND;
418                 goto done;
419         }
420
421         fstrcpy(sidstr, data.dptr);
422         sidstr_len = data.dsize;
423
424         SAFE_FREE(data.dptr);
425
426         if (sidstr_len <= 0) {
427                 DEBUG(5, ("get_object_by_name: Error unpacking database object!\n"));
428                 ret = NT_STATUS_UNSUCCESSFUL;
429                 goto done;
430         }
431
432         if (!string_to_sid(&sid, sidstr)) {
433                 DEBUG(5, ("get_object_by_name: Error invalid sid string found in database object!\n"));
434                 ret = NT_STATUS_UNSUCCESSFUL;
435                 goto done;
436         }
437
438 done:
439         if (NT_STATUS_IS_OK(ret))
440                 return get_object_by_sid(tdb, obj, &sid);
441         return ret;
442 }
443
444 /* Get object's sequence number */
445
446 static NTSTATUS get_object_seq_num(TDB_CONTEXT *tdb, GUMS_OBJECT *object, int *seq_num)
447 {
448
449         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
450         TDB_DATA data, key;
451         fstring keystr;
452         fstring sidstr;
453         int version, type, seqnum;
454
455         if (!object || !seq_num)
456                 return NT_STATUS_INVALID_PARAMETER;
457
458         fstrcpy(sidstr, sid_string_static(gums_get_object_sid(object)));
459         slprintf(keystr, sizeof(keystr)-1, "%s%s", SIDPREFIX, sidstr);
460
461         key.dptr = keystr;
462         key.dsize = strlen(keystr) + 1;
463
464         data = tdb_fetch(tdb, key);
465         if (!data.dptr) {
466                 DEBUG(5, ("get_object_seq_num: Entry not found!\n"));
467                 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdb)));
468                 DEBUGADD(5, (" Key: %s\n", keystr));
469                 ret = NT_STATUS_NOT_FOUND;
470                 goto done;
471         }
472
473         if (tdb_unpack (data.dptr, data.dsize, TDB_BASIC_OBJ_STRING, &version, &type, &seqnum) == -1)
474                 goto done;
475
476         *seq_num = seqnum;
477         ret = NT_STATUS_OK;
478
479 done:
480         SAFE_FREE(data.dptr);
481         return ret;
482 }
483
484 /* store a gums object
485  * flag: TDB_REPLACE or TDB_MODIFY or TDB_INSERT
486  */
487
488 static NTSTATUS store_object(TDB_CONTEXT *tdb, GUMS_OBJECT *object, int flag)
489 {
490         NTSTATUS ret = NT_STATUS_OK;
491         TDB_DATA data, data2, key, key2;
492         TALLOC_CTX *mem_ctx;
493         fstring keystr;
494         fstring sidstr;
495         fstring namestr;
496         fstring objname;
497         int r;
498
499         /* TODO: on object renaming/replacing this function should
500          * check name->sid record and delete the old one
501          */
502
503         mem_ctx = talloc_init("store_object");
504         if (!mem_ctx) {
505                 DEBUG(0, ("store_object: Out of memory!\n"));
506                 return NT_STATUS_NO_MEMORY;
507         }
508
509         make_full_object_name(tdb, objname, object);
510
511         /* Data is stored in all lower-case */
512         strlower_m(objname);
513
514         if (flag == TDB_MODIFY) {
515                 if (!NT_STATUS_IS_OK(ret = get_object_seq_num(tdb, object, &(object->seq_num))))
516                         goto done;
517                 object->seq_num += 1;
518         }
519
520         if (!NT_STATUS_IS_OK(ret = init_buffer_from_object(&(data.dptr), &(data.dsize), mem_ctx, object)))
521                 goto done;
522
523         fstrcpy(sidstr, sid_string_static(gums_get_object_sid(object)));
524         slprintf(keystr, sizeof(keystr) - 1, "%s%s", SIDPREFIX, sidstr);
525         slprintf(namestr, sizeof(namestr) - 1, "%s%s", NAMEPREFIX, objname);
526
527         key.dptr = keystr;
528         key.dsize = strlen(keystr) + 1;
529
530         if ((r = tdb_store(tdb, key, data, flag)) != TDB_SUCCESS) {
531                 DEBUG(0, ("store_object: Unable to modify TDBSAM!\n"));
532                 DEBUGADD(0, (" Error: %s", tdb_errorstr(tdb)));
533                 DEBUGADD(0, (" occured while storing sid record (%s)\n", keystr));
534                 if (r == TDB_ERR_EXISTS)
535                         ret = NT_STATUS_UNSUCCESSFUL;
536                 else
537                         ret = NT_STATUS_INTERNAL_DB_ERROR;
538                 goto done;
539         }
540
541         data2.dptr = sidstr;
542         data2.dsize = strlen(sidstr) + 1;
543         key2.dptr = namestr;
544         key2.dsize = strlen(namestr) + 1;
545
546         if ((r = tdb_store(tdb, key2, data2, flag)) != TDB_SUCCESS) {
547                 DEBUG(0, ("store_object: Unable to modify TDBSAM!\n"));
548                 DEBUGADD(0, (" Error: %s", tdb_errorstr(tdb)));
549                 DEBUGADD(0, (" occured while storing name record (%s)\n", keystr));
550                 DEBUGADD(0, (" attempting rollback operation.\n"));
551                 if ((tdb_delete(tdb, key)) != TDB_SUCCESS) {
552                         DEBUG(0, ("store_object: Unable to rollback! Check database consitency!\n"));
553                 }
554                 if (r == TDB_ERR_EXISTS)
555                         ret = NT_STATUS_UNSUCCESSFUL;
556                 else
557                         ret = NT_STATUS_INTERNAL_DB_ERROR;
558                 goto done;
559         }
560
561 /* TODO: update the general database counter */
562 /* TODO: update this entry counter too */
563
564 done:
565         talloc_destroy(mem_ctx);
566         return ret;
567 }
568
569 /* GUMM object functions */
570
571 static NTSTATUS tdbsam2_get_domain_sid(DOM_SID *sid, const char* name)
572 {
573
574         NTSTATUS ret;
575         TDB_CONTEXT *tdb;
576         GUMS_OBJECT *go;
577         fstring domname;
578
579         if (!sid || !name)
580                 return NT_STATUS_INVALID_PARAMETER;
581
582         if (!NT_STATUS_IS_OK(ret = opentdb(&tdb, True))) {
583                 return ret;
584         }
585
586         /* Data is stored in all lower-case */
587         fstrcpy(domname, name);
588         strlower_m(domname);
589
590         if (!NT_STATUS_IS_OK(ret = get_object_by_name(tdb, &go, domname))) {
591                 go = NULL;
592                 DEBUG(0, ("tdbsam2_get_domain_sid: Error fetching database!\n"));
593                 goto done;
594         }
595
596         if (gums_get_object_type(go) != GUMS_OBJ_DOMAIN) {
597                 DEBUG(5, ("tdbsam2_get_domain_sid: Requested object is not a domain!\n"));
598                 ret = NT_STATUS_OBJECT_TYPE_MISMATCH;
599                 goto done;
600         }
601
602         sid_copy(sid, gums_get_object_sid(go));
603
604         ret = NT_STATUS_OK;
605
606 done:
607         if (go)
608                 gums_destroy_object(&go);
609         tdb_close(tdb);
610         return ret;
611 }
612
613 static NTSTATUS get_next_sid(TDB_CONTEXT *tdb, DOM_SID *sid)
614 {
615         NTSTATUS ret;
616         GUMS_OBJECT *go;
617         DOM_SID dom_sid;
618         TDB_DATA dom_sid_key;
619         fstring dom_sid_str;
620         uint32 new_rid;
621
622         /* Find the domain SID */
623         if (!NT_STATUS_IS_OK(tdbsam2_get_domain_sid(&dom_sid, global_myname()))) {
624                 DEBUG(0, ("get_next_sid: cannot found the domain sid!!\n"));
625                 return NT_STATUS_UNSUCCESSFUL;
626         }
627
628         /* Lock the domain record */
629         sid_to_string(dom_sid_str, &dom_sid);
630         dom_sid_key.dptr = dom_sid_str;
631         dom_sid_key.dsize = strlen(dom_sid_key.dptr) + 1;
632         
633         if(tdb_chainlock(tdb, dom_sid_key) != 0) {
634                 DEBUG(0, ("get_next_sid: unable to lock domain record!\n"));
635                 return NT_STATUS_UNSUCCESSFUL;
636         }
637
638         /* Get the domain object */
639         ret = get_object_by_sid(tdb, &go, &dom_sid);
640         if (!NT_STATUS_IS_OK(ret)) {
641                 DEBUG(0, ("get_next_sid: unable to get root Domain object!\n"));
642                 ret = NT_STATUS_INTERNAL_DB_ERROR;
643                 goto done;
644         }
645
646         new_rid = gums_get_domain_next_rid(go);
647         
648         /* Increment the RID Counter */
649         gums_set_domain_next_rid(go, new_rid+1);
650         
651         /* Store back Domain object */
652         ret = store_object(tdb, go, TDB_MODIFY);
653         if (!NT_STATUS_IS_OK(ret)) {
654                 DEBUG(0, ("get_next_sid: unable to update root Domain object!\n"));
655                 ret = NT_STATUS_INTERNAL_DB_ERROR;
656                 goto done;
657         }
658
659         /* Build the Domain SID to return */
660         sid_copy(sid, &dom_sid);
661         
662         if (!sid_append_rid(sid, new_rid)) {
663                 DEBUG(0, ("get_next_sid: unable to build new SID !?!\n"));
664                 ret = NT_STATUS_UNSUCCESSFUL;
665                 goto done;
666         }
667
668         ret = NT_STATUS_OK;
669
670 done:
671         /* Unlock the Domain object */
672         tdb_chainunlock(tdb, dom_sid_key);
673
674         return ret;
675 }
676
677 /* TODO */
678         NTSTATUS (*get_sequence_number) (void);
679
680
681 extern DOM_SID global_sid_NULL;
682
683 static NTSTATUS tdbsam2_new_object(DOM_SID *sid, const char *name, const int obj_type)
684 {
685
686         NTSTATUS ret = NT_STATUS_OK;
687         TDB_CONTEXT *tdb;
688         GUMS_OBJECT *go;
689         NTTIME null_time;
690         DATA_BLOB pw;
691         const char *defpw = "NOPASSWORDXXXXXX";
692         uint8 defhours[21] = {255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255};
693
694         if (!name) {
695                 DEBUG(0, ("tdbsam2_new_object: no NULL pointers are accepted here!\n"));
696                 return NT_STATUS_INVALID_PARAMETER;
697         }
698
699         if (!NT_STATUS_IS_OK(ret = opentdb(&tdb, False))) {
700                 return ret;
701         }
702
703         if (!NT_STATUS_IS_OK(ret = gums_create_object(&go, obj_type))) {
704                 go = NULL;
705                 goto done;
706         }
707
708         if (obj_type == GUMS_OBJ_DOMAIN) {
709                 sid_copy(sid, get_global_sam_sid());
710         } else {
711                 if (!NT_STATUS_IS_OK(ret = get_next_sid(tdb, sid)))
712                         goto done;
713         }
714
715         gums_set_object_sid(go, sid);
716         gums_set_object_name(go, name);
717         gums_set_object_seq_num(go, 1);
718
719         /*obj.domain->sec_desc*/
720
721         switch (obj_type) {
722                 case GUMS_OBJ_NORMAL_USER:
723
724                         init_nt_time(&null_time);
725
726                         gums_set_user_logon_time(go, null_time);
727                         gums_set_user_logoff_time(go, null_time);
728                         gums_set_user_kickoff_time(go, null_time);
729                         gums_set_user_pass_last_set_time(go, null_time);
730                         gums_set_user_pass_can_change_time(go, null_time);
731                         gums_set_user_pass_must_change_time(go, null_time);
732
733                         pw = data_blob(defpw, NT_HASH_LEN);
734                         gums_set_user_nt_pwd(go, pw);
735                         gums_set_user_lm_pwd(go, pw);
736                         data_blob_free(&pw);
737
738                         gums_set_user_logon_divs(go, 168);
739                         gums_set_user_hours(go, 21, defhours);
740
741                         gums_set_user_bad_password_count(go, 0);
742                         gums_set_user_logon_count(go, 0);
743                         gums_set_user_unknown_6(go, 0x000004ec);
744                         break;
745
746                 case GUMS_OBJ_GROUP:
747                 case GUMS_OBJ_ALIAS:
748
749                         break;
750
751                 case GUMS_OBJ_DOMAIN:
752
753                         gums_set_domain_next_rid(go, 0x3e9);
754
755                         break;  
756
757                 default:
758                         ret = NT_STATUS_OBJECT_TYPE_MISMATCH;
759                         goto done;
760         }
761
762         ret = store_object(tdb, go, TDB_INSERT);
763
764 done:
765         if (go)
766                 gums_destroy_object(&go);
767         tdb_close(tdb);
768         return ret;
769 }
770
771 /* TODO: handle privileges objects */
772
773 static NTSTATUS tdbsam2_delete_object(const DOM_SID *sid)
774 {
775         /* TODO: need to address privilege deletion */
776         NTSTATUS ret = NT_STATUS_OK;
777         TDB_CONTEXT *tdb;
778         GUMS_OBJECT *go;
779         TDB_DATA data, key;
780         fstring keystr;
781
782         if (!sid) {
783                 DEBUG(0, ("tdbsam2_delete_object: no NULL pointers are accepted here!\n"));
784                 return NT_STATUS_INVALID_PARAMETER;
785         }
786
787         if (!NT_STATUS_IS_OK(ret = opentdb(&tdb, False))) {
788                 return ret;
789         }
790
791         slprintf(keystr, sizeof(keystr) - 1, "%s%s", SIDPREFIX, sid_string_static(sid));
792         key.dptr = keystr;
793         key.dsize = strlen(keystr) + 1;
794
795         data = tdb_fetch(tdb, key);
796         if (!data.dptr) {
797                 DEBUG(5, ("tdbsam2_delete_object: Error fetching database, SID entry not found!\n"));
798                 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdb)));
799                 DEBUGADD(5, (" Key: %s\n", keystr));
800                 ret = NT_STATUS_UNSUCCESSFUL;
801                 goto done;
802         }
803
804         if (tdb_delete(tdb, key) != TDB_SUCCESS) {
805                 DEBUG(5, ("tdbsam2_delete_object: Error deleting object!\n"));
806                 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdb)));
807                 DEBUGADD(5, (" Key: %s\n", keystr));
808                 ret = NT_STATUS_UNSUCCESSFUL;
809                 goto done;
810         }       
811
812         if (!NT_STATUS_IS_OK(init_object_from_buffer(&go, data.dptr, data.dsize))) {
813                 DEBUG(0, ("tdbsam2_delete_object: Error fetching database, malformed entry!\n"));
814                 ret = NT_STATUS_UNSUCCESSFUL;
815                 goto done;
816         }
817
818         slprintf(keystr, sizeof(keystr) - 1, "%s%s", NAMEPREFIX, gums_get_object_name(go));
819
820         key.dptr = keystr;
821         key.dsize = strlen(keystr) + 1;
822
823         if (tdb_delete(tdb, key) != TDB_SUCCESS) {
824                 DEBUG(5, ("tdbsam2_delete_object: Error deleting object!\n"));
825                 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdb)));
826                 DEBUGADD(5, (" Key: %s\n", keystr));
827                 ret = NT_STATUS_UNSUCCESSFUL;
828                 goto done;
829         }
830
831 /* TODO: update the general database counter */
832
833 done:
834         gums_destroy_object(&go);
835         SAFE_FREE(data.dptr);
836         return ret;
837 }
838
839 static NTSTATUS tdbsam2_get_object_from_sid(GUMS_OBJECT **object, const DOM_SID *sid, const int obj_type)
840 {
841         NTSTATUS ret;
842         TDB_CONTEXT *tdb;
843
844         if (!object || !sid) {
845                 DEBUG(0, ("tdbsam2_get_object_from_sid: no NULL pointers are accepted here!\n"));
846                 return NT_STATUS_INVALID_PARAMETER;
847         }
848
849         if (!NT_STATUS_IS_OK(ret = opentdb(&tdb, True))) {
850                 return ret;
851         }
852
853         ret = get_object_by_sid(tdb, object, sid);
854         if (!NT_STATUS_IS_OK(ret)) {
855                 DEBUG(0, ("tdbsam2_get_object_from_sid: %s\n", nt_errstr(ret)));
856                 goto error;
857         }
858         if (obj_type && gums_get_object_type(*object) != obj_type) {
859                 DEBUG(0, ("tdbsam2_get_object_from_sid: the object is not of the rerquested type!\n"));
860                 goto error;
861         }
862
863         tdb_close(tdb);
864         return NT_STATUS_OK;    
865
866 error:
867         gums_destroy_object(object);
868         tdb_close(tdb);
869         return ret;
870 }
871
872 static NTSTATUS tdbsam2_get_object_from_name(GUMS_OBJECT **object, const char *domain, const char *name, const int obj_type)
873 {
874         NTSTATUS ret;
875         TDB_CONTEXT *tdb;
876         fstring objname;
877
878         if (!object || !name) {
879                 DEBUG(0, ("tdbsam2_get_object_from_name: no NULL pointers are accepted here!\n"));
880                 return NT_STATUS_INVALID_PARAMETER;
881         }
882
883         if (!NT_STATUS_IS_OK(ret = opentdb(&tdb, True))) {
884                 return ret;
885         }
886
887         if (obj_type == GUMS_OBJ_DOMAIN) {
888                 fstrcpy(objname, name);
889         } else {
890                 if (!domain) {
891                         domain = global_myname();
892                 }
893                 fstrcpy(objname, domain);
894                 fstrcat(objname, "\\");
895                 fstrcat(objname, name);
896         }
897
898         *object = NULL;
899         ret = get_object_by_name(tdb, object, name);
900         if (!NT_STATUS_IS_OK(ret)) {
901                 DEBUG(0, ("tdbsam2_get_object_from_name: %s\n", nt_errstr(ret)));
902                 goto error;
903         }
904         if (obj_type && gums_get_object_type(*object) != obj_type) {
905                 DEBUG(0, ("tdbsam2_get_object_from_name: the object is not of the rerquested type!\n"));
906                 goto error;
907         }
908
909         tdb_close(tdb);
910         return NT_STATUS_OK;
911
912 error:
913         gums_destroy_object(object);
914         tdb_close(tdb);
915         return ret;
916 }
917
918         /* This function is used to get the list of all objects changed since base_time, it is
919            used to support PDC<->BDC synchronization */
920         NTSTATUS (*get_updated_objects) (GUMS_OBJECT **objects, const NTTIME base_time);
921
922 static NTSTATUS tdbsam2_enumerate_objects_start(void **handle, const DOM_SID *sid, const int obj_type)
923 {
924         struct tdbsam2_enum_objs *teo, *t;
925
926         teo = (struct tdbsam2_enum_objs *)malloc(sizeof(struct tdbsam2_enum_objs));
927         if (!teo) {
928                 DEBUG(0, ("tdbsam2_enumerate_objects_start: Out of Memory!\n"));
929                 return NT_STATUS_NO_MEMORY;
930         }
931         memset(teo, 0, sizeof(struct tdbsam2_enum_objs));
932
933         teo->type = obj_type;
934         if (sid) {
935                 teo->dom_sid = (DOM_SID *)malloc(sizeof(DOM_SID));
936                 if (!teo->dom_sid) {
937                         DEBUG(0, ("tdbsam2_enumerate_objects_start: Out of Memory!\n"));
938                         return NT_STATUS_NO_MEMORY;
939                 }
940                 sid_copy(teo->dom_sid, sid);
941         }
942
943         if (!NT_STATUS_IS_OK(opentdb(&(teo->db), True)))
944         {
945                 DEBUG(0, ("tdbsam2_enumerate_objects_start: Unable to open database (%s)!\n", ts2_privs->storage));
946                 SAFE_FREE(teo);
947                 return NT_STATUS_UNSUCCESSFUL;
948         }
949
950         if (!ts2_privs->teo_handlers) {
951                 ts2_privs->teo_handlers = teo;
952         } else {
953                 t = ts2_privs->teo_handlers;
954                 while (t->next) {
955                         t = t->next;
956                 }
957                 t->next = teo;
958         }
959
960         *handle = teo;
961
962         teo->key = tdb_firstkey(teo->db);
963
964         return NT_STATUS_OK;    
965 }
966
967 static NTSTATUS tdbsam2_enumerate_objects_get_next(GUMS_OBJECT **object, void *handle)
968 {
969         NTSTATUS ret;
970         TDB_DATA data;
971         struct tdbsam2_enum_objs *teo;
972         const char *prefix = SIDPREFIX;
973         const int preflen = strlen(prefix);
974         fstring dom_sid_str;
975         int dom_sid_str_len = 0;
976
977         if (!object || !handle) {
978                 DEBUG(0, ("tdbsam2_get_object_from_sid: no NULL pointers are accepted here!\n"));
979                 return NT_STATUS_INVALID_PARAMETER;
980         }
981
982         teo = (struct tdbsam2_enum_objs *)handle;
983
984         if (teo->dom_sid) {
985                 sid_to_string(dom_sid_str, teo->dom_sid);
986                 dom_sid_str_len = strlen(dom_sid_str);
987         }       
988
989         while ((teo->key.dptr != NULL)) {
990                 int len, version, type, size, seqnum;
991                 char *ptr;
992
993                 if (strncmp(teo->key.dptr, prefix, preflen)) {
994                         teo->key = tdb_nextkey(teo->db, teo->key);
995                         continue;
996                 }
997
998                 if (dom_sid_str_len != 0) {
999                         if (strncmp(&(teo->key.dptr[preflen]), dom_sid_str, dom_sid_str_len)) {
1000                                 teo->key = tdb_nextkey(teo->db, teo->key);
1001                                 continue;
1002                         }
1003                 }
1004
1005                 data = tdb_fetch(teo->db, teo->key);
1006                 if (!data.dptr) {
1007                         DEBUG(5, ("tdbsam2_enumerate_objects_get_next: Error fetching database, SID entry not found!\n"));
1008                         DEBUGADD(5, (" Error: %s\n", tdb_errorstr(teo->db)));
1009                         DEBUGADD(5, (" Key: %s\n", teo->key.dptr));
1010                         ret = NT_STATUS_UNSUCCESSFUL;
1011                         goto done;
1012                 }
1013
1014                 len = tdb_unpack (data.dptr, data.dsize, TDB_FORMAT_STRING,
1015                           &version,
1016                           &type,
1017                           &seqnum,
1018                           &size, &ptr);
1019
1020                 if (len == -1) {
1021                         DEBUG(5, ("tdbsam2_enumerate_objects_get_next: Error unable to unpack data!\n"));
1022                         ret = NT_STATUS_UNSUCCESSFUL;
1023                         goto done;
1024                 }
1025                 SAFE_FREE(ptr);
1026
1027                 if (teo->type && type != teo->type) {
1028                         SAFE_FREE(data.dptr);
1029                         data.dsize = 0;
1030                         teo->key = tdb_nextkey(teo->db, teo->key);
1031                         continue;
1032                 }
1033                 
1034                 break;
1035         }
1036
1037         if (teo->key.dptr == NULL) { /* no more objs */
1038                 ret = NT_STATUS_NO_MORE_ENTRIES;
1039                 goto done;
1040         }
1041
1042         if (!NT_STATUS_IS_OK(ret = init_object_from_buffer(object, data.dptr, data.dsize))) {
1043                 SAFE_FREE(data.dptr);
1044                 DEBUG(0, ("tdbsam2_enumerate_objects_get_next: Error fetching database, malformed entry!\n"));
1045                 ret = NT_STATUS_UNSUCCESSFUL;
1046                 goto done;
1047         }
1048         SAFE_FREE(data.dptr);
1049
1050         /* prepare next run */
1051         teo->key = tdb_nextkey(teo->db, teo->key);
1052
1053 done:
1054         return ret;
1055 }
1056
1057 static NTSTATUS tdbsam2_enumerate_objects_stop(void *handle)
1058 {
1059         struct tdbsam2_enum_objs *teo, *t, *p;
1060
1061         teo = (struct tdbsam2_enum_objs *)handle;
1062
1063         if (ts2_privs->teo_handlers == teo) {
1064                 ts2_privs->teo_handlers = teo->next;
1065         } else {
1066                 t = ts2_privs->teo_handlers;
1067                 while (t != teo) {
1068                         p = t;
1069                         t = t->next;
1070                         if (t == NULL) {
1071                                 DEBUG(0, ("tdbsam2_enumerate_objects_stop: Error, handle not found!\n"));
1072                                 return NT_STATUS_UNSUCCESSFUL;
1073                         }
1074                 }
1075                 p = t->next;
1076         }
1077
1078         tdb_close(teo->db);
1079         SAFE_FREE(teo->dom_sid);
1080         SAFE_FREE(teo);
1081
1082         return NT_STATUS_OK;
1083 }
1084
1085 static NTSTATUS tdbsam2_set_object(GUMS_OBJECT *go)
1086 {
1087         NTSTATUS ret;
1088         TDB_CONTEXT *tdb;
1089
1090         if (!go)
1091                 return NT_STATUS_INVALID_PARAMETER;
1092
1093         if (!NT_STATUS_IS_OK(ret = opentdb(&tdb, False))) {
1094                 return ret;
1095         }
1096
1097         ret = store_object(tdb, go, TDB_REPLACE);
1098
1099         tdb_close(tdb);
1100         return ret;
1101 }
1102
1103 #if 0
1104         /* set object values function */
1105 static NTSTATUS (*set_object_values) (DOM_SID *sid, uint32 count, GUMS_DATA_SET *data_set);
1106
1107         /* Group related functions */
1108 static NTSTATUS (*add_memberss_to_group) (const DOM_SID *group, const DOM_SID **members);
1109         NTSTATUS (*delete_members_from_group) (const DOM_SID *group, const DOM_SID **members);
1110 static NTSTATUS (*enumerate_group_members) (DOM_SID **members, const DOM_SID *sid, const int type);
1111
1112 static NTSTATUS (*get_sid_groups) (DOM_SID **groups, const DOM_SID *sid);
1113
1114 static NTSTATUS (*lock_sid) (const DOM_SID *sid);
1115 static NTSTATUS (*unlock_sid) (const DOM_SID *sid);
1116
1117         /* privileges related functions */
1118
1119 static  NTSTATUS (*get_privilege) (GUMS_OBJECT **object, const char *name);
1120 static  NTSTATUS (*add_members_to_privilege) (const char *name, const DOM_SID **members);
1121 static  NTSTATUS (*delete_members_from_privilege) (const char *name, const DOM_SID **members);
1122 static  NTSTATUS (*enumerate_privilege_members) (const char *name, DOM_SID **members);
1123 static  NTSTATUS (*get_sid_privileges) (const DOM_SID *sid, const char **privs);
1124
1125         /* warning!: set_privilege will overwrite a prior existing privilege if such exist */
1126 static  NTSTATUS (*set_privilege) (GUMS_PRIVILEGE *priv);
1127 #endif
1128
1129 static void free_tdbsam2_private_data(void **vp) 
1130 {
1131         struct tdbsam2_private_data **tdb_privs = (struct tdbsam2_private_data **)vp;
1132         while (ts2_privs->teo_handlers)
1133                 tdbsam2_enumerate_objects_stop(ts2_privs->teo_handlers);
1134         *tdb_privs = NULL;
1135         /* No need to free any further, as it is talloc()ed */
1136 }
1137
1138 static NTSTATUS init_tdbsam2(GUMS_FUNCTIONS *fns, const char *storage)
1139 {
1140         NTSTATUS ret;
1141         TDB_CONTEXT *tdb;
1142         DOM_SID dom_sid;
1143
1144         fns->name = talloc_strdup(fns->mem_ctx, "tdbsam2");
1145
1146         fns->get_domain_sid = tdbsam2_get_domain_sid;
1147         /* fns->get_sequence_number = tdbsam2_get_sequence_number; */
1148         fns->new_object = tdbsam2_new_object;
1149         fns->delete_object = tdbsam2_delete_object;
1150         fns->get_object_from_sid = tdbsam2_get_object_from_sid;
1151         fns->get_object_from_name = tdbsam2_get_object_from_name;
1152         /* fns->get_updated_objects = tdbsam2_get_updated_objects; */
1153         fns->enumerate_objects_start = tdbsam2_enumerate_objects_start;
1154         fns->enumerate_objects_get_next = tdbsam2_enumerate_objects_get_next;
1155         fns->enumerate_objects_stop = tdbsam2_enumerate_objects_stop;
1156         fns->set_object = tdbsam2_set_object;
1157         /* fns->set_object_values = tdbsam2_set_object_values;
1158         fns->add_members_to_group = tdbsam2_add_members_to_group;
1159         fns->delete_members_from_group = tdbsam2_delete_members_from_group;
1160         fns->enumerate_group_members = tdbsam2_enumerate_group_members;
1161         fns->get_sid_groups = tdbsam2_get_sid_groups;
1162         fns->lock_sid = tdbsam2_lock_sid;
1163         fns->unlock_sid = tdbsam2_unlock_sid;
1164         fns->get_privilege = tdbsam2_get_privilege;
1165         fns->add_members_to_privilege = tdbsam2_add_members_to_privilege;
1166         fns->delete_members_from_privilege = tdbsam2_delete_members_from_privilege;
1167         fns->enumerate_privilege_members = tdbsam2_enumerate_privilege_members;
1168         fns->get_sid_privileges = tdbsam2_get_sid_privileges;
1169         fns->set_privilege = tdbsam2_set_privilege; */
1170
1171         ts2_privs = talloc_zero(fns->mem_ctx, sizeof(struct tdbsam2_private_data));
1172         if (!ts2_privs) {
1173                 DEBUG(0, ("talloc() failed for tdbsam2 private_data!\n"));
1174                 return NT_STATUS_NO_MEMORY;
1175         }
1176
1177         if (storage) {
1178                 ts2_privs->storage = talloc_strdup(fns->mem_ctx, storage);
1179         } else {
1180                 pstring tdbfile;
1181                 get_private_directory(tdbfile);
1182                 pstrcat(tdbfile, "/");
1183                 pstrcat(tdbfile, TDB_FILE_NAME);
1184                 ts2_privs->storage = talloc_strdup(fns->mem_ctx, tdbfile);
1185         }
1186
1187         /* check tdb exist (or create it) */
1188
1189                 /* Find the domain SID */
1190         if (!NT_STATUS_IS_OK(tdbsam2_get_domain_sid(&dom_sid, global_myname()))) {
1191                 /* db file does not exist or it is not inited */
1192                         /* make the tdb file */
1193                 if (!NT_STATUS_IS_OK(ret = opentdb(&tdb, False))) {
1194                         return ret;
1195                 }
1196                 tdb_close(tdb);
1197
1198                 if (!NT_STATUS_IS_OK(tdbsam2_get_domain_sid(&dom_sid, "BUILTIN"))) {
1199                         gums_init_builtin_domain();
1200                 }
1201
1202                 gums_init_domain(get_global_sam_sid(), global_myname(), "The Domain");
1203         }
1204
1205         fns->private_data = &ts2_privs;
1206         fns->free_private_data = free_tdbsam2_private_data;
1207
1208         return NT_STATUS_OK;
1209 }
1210
1211 NTSTATUS gums_tdbsam2_init(void)
1212 {
1213         /*
1214         if ((gums_tdbsam2_debug_class = debug_add_class("gums_tdbsam2")) == -1) {
1215                 DEBUG(0, ("gums_tdbsam2: unable to register my own debug class! going on ...\n"));
1216                 gums_tdbsam2_debug_class = DBGC_ALL;
1217         } 
1218         */
1219         return gums_register_module(GUMS_INTERFACE_VERSION, "tdbsam2", init_tdbsam2);
1220 }