r15783: Fix previous commit, was the wrong way to deal with the problem
[kai/samba.git] / source4 / dsdb / samdb / ldb_modules / samldb.c
1 /* 
2    SAM ldb module
3
4    Copyright (C) Simo Sorce  2004
5    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
6
7    * NOTICE: this module is NOT released under the GNU LGPL license as
8    * other ldb code. This module is release under the GNU GPL v2 or
9    * later license.
10
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 2 of the License, or
14    (at your option) any later version.
15    
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20    
21    You should have received a copy of the GNU General Public License
22    along with this program; if not, write to the Free Software
23    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26 /*
27  *  Name: ldb
28  *
29  *  Component: ldb samldb module
30  *
31  *  Description: add embedded user/group creation functionality
32  *
33  *  Author: Simo Sorce
34  */
35
36 #include "includes.h"
37 #include "libcli/ldap/ldap.h"
38 #include "lib/ldb/include/ldb_errors.h"
39 #include "lib/ldb/include/ldb_private.h"
40 #include "dsdb/samdb/samdb.h"
41 #include "libcli/security/security.h"
42 #include "librpc/gen_ndr/ndr_security.h"
43 #include "db_wrap.h"
44
45
46 /* if value is not null also check for attribute to have exactly that value */
47 static struct ldb_message_element *samldb_find_attribute(const struct ldb_message *msg, const char *name, const char *value)
48 {
49         int j;
50         struct ldb_message_element *el = ldb_msg_find_element(msg, name);
51         if (!el) {
52                 return NULL;
53         }
54
55         if (!value) {
56                 return el;
57         }
58
59         for (j = 0; j < el->num_values; j++) {
60                 if (strcasecmp(value, 
61                                (char *)el->values[j].data) == 0) {
62                         return el;
63                 }
64         }
65
66         return NULL;
67 }
68
69 static BOOL samldb_msg_add_string(struct ldb_module *module, struct ldb_message *msg, const char *name, const char *value)
70 {
71         char *aval = talloc_strdup(msg, value);
72
73         if (aval == NULL) {
74                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_msg_add_string: talloc_strdup failed!\n");
75                 return False;
76         }
77
78         if (ldb_msg_add_string(msg, name, aval) != 0) {
79                 return False;
80         }
81
82         return True;
83 }
84
85 static BOOL samldb_msg_add_sid(struct ldb_module *module, struct ldb_message *msg, const char *name, const struct dom_sid *sid)
86 {
87         struct ldb_val v;
88         NTSTATUS status;
89         status = ndr_push_struct_blob(&v, msg, sid, 
90                                       (ndr_push_flags_fn_t)ndr_push_dom_sid);
91         if (!NT_STATUS_IS_OK(status)) {
92                 return -1;
93         }
94         return (ldb_msg_add_value(msg, name, &v) == 0);
95 }
96
97 static BOOL samldb_find_or_add_attribute(struct ldb_module *module, struct ldb_message *msg, const char *name, const char *value, const char *set_value)
98 {
99         if (samldb_find_attribute(msg, name, value) == NULL) {
100                 return samldb_msg_add_string(module, msg, name, set_value);
101         }
102         return True;
103 }
104
105 /*
106   allocate a new id, attempting to do it atomically
107   return 0 on failure, the id on success
108 */
109 static int samldb_set_next_rid(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
110                                const struct ldb_dn *dn, uint32_t old_id, uint32_t new_id)
111 {
112         struct ldb_message msg;
113         int ret;
114         struct ldb_val vals[2];
115         struct ldb_message_element els[2];
116
117         if (new_id == 0) {
118                 /* out of IDs ! */
119                 ldb_debug(ldb, LDB_DEBUG_FATAL, "Are we out of valid IDs ?\n");
120                 return LDB_ERR_OPERATIONS_ERROR;
121         }
122
123         /* we do a delete and add as a single operation. That prevents
124            a race, in case we are not actually on a transaction db */
125         ZERO_STRUCT(msg);
126         msg.dn = ldb_dn_copy(mem_ctx, dn);
127         if (!msg.dn) {
128                 return LDB_ERR_OPERATIONS_ERROR;
129         }
130         msg.num_elements = 2;
131         msg.elements = els;
132
133         els[0].num_values = 1;
134         els[0].values = &vals[0];
135         els[0].flags = LDB_FLAG_MOD_DELETE;
136         els[0].name = talloc_strdup(mem_ctx, "nextRid");
137         if (!els[0].name) {
138                 return LDB_ERR_OPERATIONS_ERROR;
139         }
140
141         els[1].num_values = 1;
142         els[1].values = &vals[1];
143         els[1].flags = LDB_FLAG_MOD_ADD;
144         els[1].name = els[0].name;
145
146         vals[0].data = (uint8_t *)talloc_asprintf(mem_ctx, "%u", old_id);
147         if (!vals[0].data) {
148                 return LDB_ERR_OPERATIONS_ERROR;
149         }
150         vals[0].length = strlen((char *)vals[0].data);
151
152         vals[1].data = (uint8_t *)talloc_asprintf(mem_ctx, "%u", new_id);
153         if (!vals[1].data) {
154                 return LDB_ERR_OPERATIONS_ERROR;
155         }
156         vals[1].length = strlen((char *)vals[1].data);
157
158         ret = ldb_modify(ldb, &msg);
159         return ret;
160 }
161
162 /*
163   allocate a new id, attempting to do it atomically
164   return 0 on failure, the id on success
165 */
166 static int samldb_find_next_rid(struct ldb_module *module, TALLOC_CTX *mem_ctx,
167                                 const struct ldb_dn *dn, uint32_t *old_rid)
168 {
169         const char * const attrs[2] = { "nextRid", NULL };
170         struct ldb_result *res = NULL;
171         int ret;
172         const char *str;
173
174         ret = ldb_search(module->ldb, dn, LDB_SCOPE_BASE, "nextRid=*", attrs, &res);
175         if (ret != LDB_SUCCESS) {
176                 return ret;
177         }
178         talloc_steal(mem_ctx, res);
179         if (res->count != 1) {
180                 talloc_free(res);
181                 return -1;
182         }
183
184         str = ldb_msg_find_string(res->msgs[0], "nextRid", NULL);
185         if (str == NULL) {
186                 ldb_set_errstring(module->ldb,
187                                   talloc_asprintf(mem_ctx, "attribute nextRid not found in %s\n",
188                                                   ldb_dn_linearize(res, dn)));
189                 talloc_free(res);
190                 return -1;
191         }
192
193         *old_rid = strtol(str, NULL, 0);
194         talloc_free(res);
195         return 0;
196 }
197
198 static int samldb_allocate_next_rid(struct ldb_module *module, TALLOC_CTX *mem_ctx,
199                                     const struct ldb_dn *dn, const struct dom_sid *dom_sid, 
200                                     struct dom_sid **new_sid)
201 {
202         struct dom_sid *obj_sid;
203         uint32_t old_rid;
204         int ret;
205         struct ldb_message **sid_msgs;
206         const char *sid_attrs[] = { NULL };
207         
208         do {
209                 ret = samldb_find_next_rid(module, mem_ctx, dn, &old_rid);      
210                 if (ret) {
211                         return ret;
212                 }
213                 
214                 /* return the new object sid */
215                 obj_sid = dom_sid_add_rid(mem_ctx, dom_sid, old_rid);
216                 
217                 ret = samldb_set_next_rid(module->ldb, mem_ctx, dn, old_rid, old_rid + 1);
218                 if (ret != 0) {
219                         return ret;
220                 }
221
222                 *new_sid = dom_sid_add_rid(mem_ctx, dom_sid, old_rid + 1);
223                 if (!*new_sid) {
224                         return LDB_ERR_OPERATIONS_ERROR;
225                 }
226
227                 ret = gendb_search(module->ldb,
228                                    mem_ctx, NULL, &sid_msgs, sid_attrs,
229                                    "objectSid=%s",
230                                    ldap_encode_ndr_dom_sid(mem_ctx, *new_sid));
231                 if (ret == 0) {
232                         /* Great. There are no conflicting users/groups/etc */
233                         return 0;
234                 } else if (ret == -1) {
235                         /* Bugger, there is a problem, and we don't know what it is until gendb_search improves */
236                         return ret;
237                 } else {
238                         /* gah, there are conflicting sids, lets move around the loop again... */
239                 }
240         } while (1);
241         return ret;
242 }
243
244 /* Find a domain object in the parents of a particular DN.  */
245 static struct ldb_dn *samldb_search_domain(struct ldb_module *module, TALLOC_CTX *mem_ctx, const struct ldb_dn *dn)
246 {
247         TALLOC_CTX *local_ctx;
248         struct ldb_dn *sdn;
249         struct ldb_result *res = NULL;
250         int ret = 0;
251
252         local_ctx = talloc_new(mem_ctx);
253         if (local_ctx == NULL) return NULL;
254
255         sdn = ldb_dn_copy(local_ctx, dn);
256         do {
257                 ret = ldb_search(module->ldb, sdn, LDB_SCOPE_BASE, "objectClass=domain", NULL, &res);
258                 talloc_steal(local_ctx, res);
259                 if (ret == LDB_SUCCESS && res->count == 1)
260                         break;
261         } while ((sdn = ldb_dn_get_parent(local_ctx, sdn)));
262
263         if (ret != LDB_SUCCESS || res->count != 1) {
264                 talloc_free(local_ctx);
265                 return NULL;
266         }
267
268         talloc_steal(mem_ctx, sdn);
269         talloc_free(local_ctx);
270
271         return sdn;
272 }
273
274 /* search the domain related to the provided dn
275    allocate a new RID for the domain
276    return the new sid string
277 */
278 static struct dom_sid *samldb_get_new_sid(struct ldb_module *module, 
279                                           TALLOC_CTX *mem_ctx, const struct ldb_dn *obj_dn)
280 {
281         const char * const attrs[2] = { "objectSid", NULL };
282         struct ldb_result *res = NULL;
283         const struct ldb_dn *dom_dn;
284         int ret;
285         struct dom_sid *dom_sid, *obj_sid;
286
287         /* get the domain component part of the provided dn */
288
289         dom_dn = samldb_search_domain(module, mem_ctx, obj_dn);
290         if (dom_dn == NULL) {
291                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Invalid dn (%s) not child of a domain object!\n", ldb_dn_linearize(mem_ctx, obj_dn));
292                 return NULL;
293         }
294
295         /* find the domain sid */
296
297         ret = ldb_search(module->ldb, dom_dn, LDB_SCOPE_BASE, "objectSid=*", attrs, &res);
298         if (ret != LDB_SUCCESS || res->count != 1) {
299                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_get_new_sid: error retrieving domain sid!\n");
300                 talloc_free(res);
301                 return NULL;
302         }
303
304         dom_sid = samdb_result_dom_sid(res, res->msgs[0], "objectSid");
305         if (dom_sid == NULL) {
306                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_get_new_sid: error retrieving domain sid!\n");
307                 talloc_free(res);
308                 return NULL;
309         }
310
311         /* allocate a new Rid for the domain */
312         ret = samldb_allocate_next_rid(module, mem_ctx, dom_dn, dom_sid, &obj_sid);
313         if (ret != 0) {
314                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Failed to increment nextRid of %s\n", ldb_dn_linearize(mem_ctx, dom_dn));
315                 talloc_free(res);
316                 return NULL;
317         }
318
319         talloc_free(res);
320
321         return obj_sid;
322 }
323
324 /* If we are adding new users/groups, we need to update the nextRid
325  * attribute to be 'above' all incoming users RIDs.  This tries to
326  * avoid clashes in future */
327
328 int samldb_notice_sid(struct ldb_module *module, 
329                       TALLOC_CTX *mem_ctx, const struct dom_sid *sid)
330 {
331         int ret;
332         struct ldb_dn *dom_dn;
333         struct dom_sid *dom_sid;
334         const char *dom_attrs[] = { NULL };
335         struct ldb_message **dom_msgs;
336         uint32_t old_rid;
337
338         /* find the domain DN */
339
340         ret = gendb_search(module->ldb,
341                            mem_ctx, NULL, &dom_msgs, dom_attrs,
342                            "objectSid=%s",
343                            ldap_encode_ndr_dom_sid(mem_ctx, sid));
344         if (ret > 0) {
345                 ldb_set_errstring(module->ldb,
346                                   talloc_asprintf(mem_ctx,
347                                                   "Attempt to add record with SID %s rejected,"
348                                                   " because this SID is already in the database",
349                                                   dom_sid_string(mem_ctx, sid)));
350                 /* We have a duplicate SID, we must reject the add */
351                 talloc_free(dom_msgs);
352                 return LDB_ERR_CONSTRAINT_VIOLATION;
353         }
354         
355         if (ret == -1) {
356                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_get_new_sid: error searching for proposed sid!\n");
357                 return -1;
358         }
359
360         dom_sid = dom_sid_dup(mem_ctx, sid);
361         if (!dom_sid) {
362                 return LDB_ERR_OPERATIONS_ERROR;
363         }
364         /* get the domain component part of the provided SID */
365         dom_sid->num_auths--;
366
367         /* find the domain DN */
368
369         ret = gendb_search(module->ldb,
370                            mem_ctx, NULL, &dom_msgs, dom_attrs,
371                            "(&(objectSid=%s)(objectclass=domain))",
372                            ldap_encode_ndr_dom_sid(mem_ctx, dom_sid));
373         if (ret == 0) {
374                 /* This isn't an operation on a domain we know about, so nothing to update */
375                 return 0;
376         }
377
378         if (ret > 1) {
379                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_get_new_sid: error retrieving domain from sid: duplicate domains!\n");
380                 talloc_free(dom_msgs);
381                 return -1;
382         }
383
384         if (ret != 1) {
385                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_get_new_sid: error retrieving domain sid!\n");
386                 return -1;
387         }
388
389         dom_dn = dom_msgs[0]->dn;
390
391         ret = samldb_find_next_rid(module, mem_ctx, 
392                                    dom_dn, &old_rid);
393         if (ret) {
394                 talloc_free(dom_msgs);
395                 return ret;
396         }
397
398         if (old_rid <= sid->sub_auths[sid->num_auths - 1]) {
399                 ret = samldb_set_next_rid(module->ldb, mem_ctx, dom_dn, old_rid, 
400                                           sid->sub_auths[sid->num_auths - 1] + 1);
401         }
402         talloc_free(dom_msgs);
403         return ret;
404 }
405
406 static int samldb_handle_sid(struct ldb_module *module, 
407                                          TALLOC_CTX *mem_ctx, struct ldb_message *msg2)
408 {
409         int ret;
410         
411         struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg2, "objectSid");
412         if (sid == NULL) { 
413                 sid = samldb_get_new_sid(module, msg2, msg2->dn);
414                 if (sid == NULL) {
415                         ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_user_or_computer_object: internal error! Can't generate new sid\n");
416                         return LDB_ERR_OPERATIONS_ERROR;
417                 }
418
419                 if ( ! samldb_msg_add_sid(module, msg2, "objectSid", sid)) {
420                         talloc_free(sid);
421                         return LDB_ERR_OPERATIONS_ERROR;
422                 }
423                 talloc_free(sid);
424                 ret = 0;
425         } else {
426                 ret = samldb_notice_sid(module, msg2, sid);
427         }
428         return ret;
429 }
430
431 static char *samldb_generate_samAccountName(struct ldb_module *module, TALLOC_CTX *mem_ctx) 
432 {
433         char *name;
434         const char *attrs[] = { NULL };
435         struct ldb_message **msgs;
436         int ret;
437         
438         /* Format: $000000-000000000000 */
439         
440         do {
441                 name = talloc_asprintf(mem_ctx, "$%.6X-%.6X%.6X", (unsigned int)random(), (unsigned int)random(), (unsigned int)random());
442                 /* TODO: Figure out exactly what this is meant to conflict with */
443                 ret = gendb_search(module->ldb,
444                                    mem_ctx, NULL, &msgs, attrs,
445                                    "samAccountName=%s",
446                                    ldb_binary_encode_string(mem_ctx, name));
447                 if (ret == 0) {
448                         /* Great. There are no conflicting users/groups/etc */
449                         return name;
450                 } else if (ret == -1) {
451                         /* Bugger, there is a problem, and we don't know what it is until gendb_search improves */
452                         return NULL;
453                 } else {
454                         talloc_free(name);
455                         /* gah, there are conflicting sids, lets move around the loop again... */
456                 }
457         } while (1);
458 }
459
460 static int samldb_copy_template(struct ldb_module *module, struct ldb_message *msg, const char *filter)
461 {
462         struct ldb_result *res;
463         struct ldb_message *t;
464         int ret, i, j;
465         
466
467         /* pull the template record */
468         ret = ldb_search(module->ldb, NULL, LDB_SCOPE_SUBTREE, filter, NULL, &res);
469         if (ret != LDB_SUCCESS || res->count != 1) {
470                 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "samldb: ERROR: template '%s' matched too many records\n", filter);
471                 return -1;
472         }
473         t = res->msgs[0];
474
475         for (i = 0; i < t->num_elements; i++) {
476                 struct ldb_message_element *el = &t->elements[i];
477                 /* some elements should not be copied from the template */
478                 if (strcasecmp(el->name, "cn") == 0 ||
479                     strcasecmp(el->name, "name") == 0 ||
480                     strcasecmp(el->name, "sAMAccountName") == 0 ||
481                     strcasecmp(el->name, "objectGUID") == 0) {
482                         continue;
483                 }
484                 for (j = 0; j < el->num_values; j++) {
485                         if (strcasecmp(el->name, "objectClass") == 0) {
486                                 if (strcasecmp((char *)el->values[j].data, "Template") == 0 ||
487                                     strcasecmp((char *)el->values[j].data, "userTemplate") == 0 ||
488                                     strcasecmp((char *)el->values[j].data, "groupTemplate") == 0 ||
489                                     strcasecmp((char *)el->values[j].data, "foreignSecurityPrincipalTemplate") == 0 ||
490                                     strcasecmp((char *)el->values[j].data, "aliasTemplate") == 0 || 
491                                     strcasecmp((char *)el->values[j].data, "trustedDomainTemplate") == 0 || 
492                                     strcasecmp((char *)el->values[j].data, "secretTemplate") == 0) {
493                                         continue;
494                                 }
495                                 if ( ! samldb_find_or_add_attribute(module, msg, el->name, 
496                                                                     (char *)el->values[j].data,
497                                                                     (char *)el->values[j].data)) {
498                                         ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Attribute adding failed...\n");
499                                         talloc_free(res);
500                                         return -1;
501                                 }
502                         } else {
503                                 if ( ! samldb_find_or_add_attribute(module, msg, el->name, 
504                                                                     NULL,
505                                                                     (char *)el->values[j].data)) {
506                                         ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Attribute adding failed...\n");
507                                         talloc_free(res);
508                                         return -1;
509                                 }
510                         }
511                 }
512         }
513
514         talloc_free(res);
515
516         return 0;
517 }
518
519 static int samldb_fill_group_object(struct ldb_module *module, const struct ldb_message *msg,
520                                                     struct ldb_message **ret_msg)
521 {
522         int ret;
523         const char *name;
524         struct ldb_message *msg2;
525         struct ldb_dn_component *rdn;
526         TALLOC_CTX *mem_ctx = talloc_new(msg);
527         if (!mem_ctx) {
528                 return LDB_ERR_OPERATIONS_ERROR;
529         }
530
531         /* build the new msg */
532         msg2 = ldb_msg_copy(mem_ctx, msg);
533         if (!msg2) {
534                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_group_object: ldb_msg_copy failed!\n");
535                 talloc_free(mem_ctx);
536                 return LDB_ERR_OPERATIONS_ERROR;
537         }
538
539         ret = samldb_copy_template(module, msg2, "(&(CN=TemplateGroup)(objectclass=groupTemplate))");
540         if (ret != 0) {
541                 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "samldb_fill_group_object: Error copying template!\n");
542                 talloc_free(mem_ctx);
543                 return ret;
544         }
545
546         rdn = ldb_dn_get_rdn(msg2, msg2->dn);
547
548         if (strcasecmp(rdn->name, "cn") != 0) {
549                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_group_object: Bad RDN (%s) for group!\n", rdn->name);
550                 talloc_free(mem_ctx);
551                 return LDB_ERR_CONSTRAINT_VIOLATION;
552         }
553
554         /* Generate a random name, if no samAccountName was supplied */
555         if (ldb_msg_find_element(msg2, "samAccountName") == NULL) {
556                 name = samldb_generate_samAccountName(module, mem_ctx);
557                 if (!name) {
558                         talloc_free(mem_ctx);
559                         return LDB_ERR_OPERATIONS_ERROR;
560                 }
561                 if ( ! samldb_find_or_add_attribute(module, msg2, "sAMAccountName", NULL, name)) {
562                         talloc_free(mem_ctx);
563                         return LDB_ERR_OPERATIONS_ERROR;
564                 }
565         }
566         
567         /* Manage SID allocation, conflicts etc */
568         ret = samldb_handle_sid(module, mem_ctx, msg2); 
569
570         if (ret == 0) {
571                 talloc_steal(msg, msg2);
572                 *ret_msg = msg2;
573         }
574         talloc_free(mem_ctx);
575         return 0;
576 }
577
578 static int samldb_fill_user_or_computer_object(struct ldb_module *module, const struct ldb_message *msg,
579                                                                struct ldb_message **ret_msg)
580 {
581         int ret;
582         char *name;
583         struct ldb_message *msg2;
584         struct ldb_dn_component *rdn;
585         TALLOC_CTX *mem_ctx = talloc_new(msg);
586         if (!mem_ctx) {
587                 return LDB_ERR_OPERATIONS_ERROR;
588         }
589
590         /* build the new msg */
591         msg2 = ldb_msg_copy(mem_ctx, msg);
592         if (!msg2) {
593                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_group_object: ldb_msg_copy failed!\n");
594                 talloc_free(mem_ctx);
595                 return LDB_ERR_OPERATIONS_ERROR;
596         }
597
598         if (samldb_find_attribute(msg, "objectclass", "computer") != NULL) {
599                 ret = samldb_copy_template(module, msg2, "(&(CN=TemplateComputer)(objectclass=userTemplate))");
600                 if (ret) {
601                         ldb_debug(module->ldb, LDB_DEBUG_WARNING, "samldb_fill_user_or_computer_object: Error copying computer template!\n");
602                         talloc_free(mem_ctx);
603                         return ret;
604                 }
605         } else {
606                 ret = samldb_copy_template(module, msg2, "(&(CN=TemplateUser)(objectclass=userTemplate))");
607                 if (ret) {
608                         ldb_debug(module->ldb, LDB_DEBUG_WARNING, "samldb_fill_user_or_computer_object: Error copying user template!\n");
609                         talloc_free(mem_ctx);
610                         return ret;
611                 }
612         }
613
614         rdn = ldb_dn_get_rdn(msg2, msg2->dn);
615
616         if (strcasecmp(rdn->name, "cn") != 0) {
617                 ldb_set_errstring(module->ldb, talloc_asprintf(module, "Bad RDN (%s=) for user/computer, should be CN=!\n", rdn->name));
618                 talloc_free(mem_ctx);
619                 return LDB_ERR_CONSTRAINT_VIOLATION;
620         }
621
622         /* if the only attribute was: "objectclass: computer", then make sure we also add "user" objectclass */
623         if ( ! samldb_find_or_add_attribute(module, msg2, "objectclass", "user", "user")) {
624                 talloc_free(mem_ctx);
625                 return LDB_ERR_OPERATIONS_ERROR;
626         }
627
628         /* make sure we also add person, organizationalPerson and top */
629         if ( ! samldb_find_or_add_attribute(module, msg2, "objectclass", "person", "person")) {
630                 talloc_free(mem_ctx);
631                 return LDB_ERR_OPERATIONS_ERROR;
632         }
633         if ( ! samldb_find_or_add_attribute(module, msg2, "objectclass", "organizationalPerson", "organizationalPerson")) {
634                 talloc_free(mem_ctx);
635                 return LDB_ERR_OPERATIONS_ERROR;
636         }
637         if ( ! samldb_find_or_add_attribute(module, msg2, "objectclass", "top", "top")) {
638                 talloc_free(mem_ctx);
639                 return LDB_ERR_OPERATIONS_ERROR;
640         }
641
642         /* meddle with objectclass */
643
644         if (ldb_msg_find_element(msg2, "samAccountName") == NULL) {
645                 name = samldb_generate_samAccountName(module, mem_ctx);
646                 if (!name) {
647                         talloc_free(mem_ctx);
648                         return LDB_ERR_OPERATIONS_ERROR;
649                 }
650                 if ( ! samldb_find_or_add_attribute(module, msg2, "sAMAccountName", NULL, name)) {
651                         talloc_free(mem_ctx);
652                         return LDB_ERR_OPERATIONS_ERROR;
653                 }
654         }
655
656         /*
657           TODO: useraccountcontrol: setting value 0 gives 0x200 for users
658         */
659
660         /* Manage SID allocation, conflicts etc */
661         ret = samldb_handle_sid(module, mem_ctx, msg2); 
662
663         /* TODO: objectCategory, userAccountControl, badPwdCount, codePage, countryCode, badPasswordTime, lastLogoff, lastLogon, pwdLastSet, primaryGroupID, accountExpires, logonCount */
664
665         if (ret == 0) {
666                 *ret_msg = msg2;
667                 talloc_steal(msg, msg2);
668         }
669         talloc_free(mem_ctx);
670         return 0;
671 }
672         
673 static int samldb_fill_foreignSecurityPrincipal_object(struct ldb_module *module, const struct ldb_message *msg, 
674                                                                        struct ldb_message **ret_msg)
675 {
676         struct ldb_message *msg2;
677         struct ldb_dn_component *rdn;
678         struct dom_sid *dom_sid;
679         struct dom_sid *sid;
680         const char *dom_attrs[] = { "name", NULL };
681         struct ldb_message **dom_msgs;
682         int ret;
683
684         TALLOC_CTX *mem_ctx = talloc_new(msg);
685         if (!mem_ctx) {
686                 return LDB_ERR_OPERATIONS_ERROR;
687         }
688
689         /* build the new msg */
690         msg2 = ldb_msg_copy(mem_ctx, msg);
691         if (!msg2) {
692                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_foreignSecurityPrincpal_object: ldb_msg_copy failed!\n");
693                 talloc_free(mem_ctx);
694                 return LDB_ERR_OPERATIONS_ERROR;
695         }
696
697         ret = samldb_copy_template(module, msg2, "(&(CN=TemplateForeignSecurityPrincipal)(objectclass=foreignSecurityPrincipalTemplate))");
698         if (ret != 0) {
699                 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "samldb_fill_foreignSecurityPrincipal_object: Error copying template!\n");
700                 talloc_free(mem_ctx);
701                 return ret;
702         }
703
704         rdn = ldb_dn_get_rdn(msg2, msg2->dn);
705
706         if (strcasecmp(rdn->name, "cn") != 0) {
707                 ldb_set_errstring(module->ldb, talloc_asprintf(module, "Bad RDN (%s=) for ForeignSecurityPrincipal, should be CN=!", rdn->name));
708                 talloc_free(mem_ctx);
709                 return LDB_ERR_CONSTRAINT_VIOLATION;
710         }
711
712         /* Slightly different for the foreign sids.  We don't want
713          * domain SIDs ending up there, it would cause all sorts of
714          * pain */
715
716         sid = dom_sid_parse_talloc(msg2, (const char *)rdn->value.data);
717         if (!sid) {
718                 ldb_set_errstring(module->ldb, talloc_asprintf(module, "No valid found SID in ForeignSecurityPrincipal CN!"));
719                 talloc_free(mem_ctx);
720                 return LDB_ERR_CONSTRAINT_VIOLATION;
721         }
722
723         if ( ! samldb_msg_add_sid(module, msg2, "objectSid", sid)) {
724                 talloc_free(sid);
725                 return LDB_ERR_OPERATIONS_ERROR;
726         }
727
728         dom_sid = dom_sid_dup(mem_ctx, sid);
729         if (!dom_sid) {
730                 talloc_free(mem_ctx);
731                 return LDB_ERR_OPERATIONS_ERROR;
732         }
733         /* get the domain component part of the provided SID */
734         dom_sid->num_auths--;
735
736         /* find the domain DN */
737
738         ret = gendb_search(module->ldb,
739                            mem_ctx, NULL, &dom_msgs, dom_attrs,
740                            "(&(objectSid=%s)(objectclass=domain))",
741                            ldap_encode_ndr_dom_sid(mem_ctx, dom_sid));
742         if (ret >= 1) {
743                 const char *name = samdb_result_string(dom_msgs[0], "name", NULL);
744                 ldb_set_errstring(module->ldb, talloc_asprintf(mem_ctx, "Attempt to add foreign SID record with SID %s rejected, because this domian (%s) is already in the database", dom_sid_string(mem_ctx, sid), name)); 
745                 /* We don't really like the idea of foreign sids that are not foreign */
746                 return LDB_ERR_CONSTRAINT_VIOLATION;
747         } else if (ret == -1) {
748                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_foreignSecurityPrincipal_object: error searching for a domain with this sid: %s\n", dom_sid_string(mem_ctx, dom_sid));
749                 talloc_free(dom_msgs);
750                 return -1;
751         }
752
753         /* This isn't an operation on a domain we know about, so just
754          * check for the SID, looking for duplicates via the common
755          * code */
756         ret = samldb_notice_sid(module, msg2, sid);
757         if (ret == 0) {
758                 talloc_steal(msg, msg2);
759                 *ret_msg = msg2;
760         }
761         
762         return ret;
763 }
764
765 /* add_record */
766 static int samldb_add(struct ldb_module *module, struct ldb_request *req)
767 {
768         struct ldb_message *msg = req->op.add.message;
769         struct ldb_message *msg2 = NULL;
770         int ret;
771
772         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "samldb_add_record\n");
773
774         
775         if (ldb_dn_is_special(msg->dn)) { /* do not manipulate our control entries */
776                 return ldb_next_request(module, req);
777         }
778
779         /* is user or computer? */
780         if ((samldb_find_attribute(msg, "objectclass", "user") != NULL) ||
781             (samldb_find_attribute(msg, "objectclass", "computer") != NULL)) {
782                 /*  add all relevant missing objects */
783                 ret = samldb_fill_user_or_computer_object(module, msg, &msg2);
784                 if (ret) {
785                         return ret;
786                 }
787         }
788
789         /* is group? add all relevant missing objects */
790         if ( ! msg2 ) {
791                 if (samldb_find_attribute(msg, "objectclass", "group") != NULL) {
792                         ret = samldb_fill_group_object(module, msg, &msg2);
793                         if (ret) {
794                                 return ret;
795                         }
796                 }
797         }
798
799         /* perhaps a foreignSecurityPrincipal? */
800         if ( ! msg2 ) {
801                 if (samldb_find_attribute(msg, "objectclass", "foreignSecurityPrincipal") != NULL) {
802                         ret = samldb_fill_foreignSecurityPrincipal_object(module, msg, &msg2);
803                         if (ret) {
804                                 return ret;
805                         }
806                 }
807         }
808
809         if (msg2) {
810                 req->op.add.message = msg2;
811                 ret = ldb_next_request(module, req);
812                 req->op.add.message = msg;
813         } else {
814                 ret = ldb_next_request(module, req);
815         }
816
817         return ret;
818 }
819
820 /* add_record */
821
822 /*
823  * FIXME
824  *
825  * Actually this module is not async at all as it does a number of sync searches
826  * in the process. It still to be decided how to deal with it properly so it is
827  * left SYNC for now until we think of a good solution.
828  */
829
830 static int samldb_add_async(struct ldb_module *module, struct ldb_request *req)
831 {
832         const struct ldb_message *msg = req->op.add.message;
833         struct ldb_message *msg2 = NULL;
834         struct ldb_request *down_req;
835         int ret;
836
837         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "samldb_add_record\n");
838
839         if (ldb_dn_is_special(msg->dn)) { /* do not manipulate our control entries */
840                 return ldb_next_request(module, req);
841         }
842
843         /* is user or computer? */
844         if ((samldb_find_attribute(msg, "objectclass", "user") == NULL) &&
845             (samldb_find_attribute(msg, "objectclass", "computer") == NULL)) {
846                 /*  add all relevant missing objects */
847                 ret = samldb_fill_user_or_computer_object(module, msg, &msg2);
848                 if (ret) {
849                         return ret;
850                 }
851         }
852
853         /* is group? add all relevant missing objects */
854         if ( ! msg2 ) {
855                 if (samldb_find_attribute(msg, "objectclass", "group") != NULL) {
856                         ret = samldb_fill_group_object(module, msg, &msg2);
857                         if (ret) {
858                                 return ret;
859                         }
860                 }
861         }
862
863         /* perhaps a foreignSecurityPrincipal? */
864         if ( ! msg2 ) {
865                 if (samldb_find_attribute(msg, "objectclass", "foreignSecurityPrincipal") != NULL) {
866                         ret = samldb_fill_foreignSecurityPrincipal_object(module, msg, &msg2);
867                         if (ret) {
868                                 return ret;
869                         }
870                 }
871         }
872
873         if (msg2 == NULL) {
874                 return ldb_next_request(module, req);
875         }
876
877         down_req = talloc(module, struct ldb_request);
878         if (down_req == NULL) {
879                 return LDB_ERR_OPERATIONS_ERROR;
880         }
881
882         *down_req = *req;
883         
884         down_req->op.add.message = talloc_steal(down_req, msg2);
885         
886         /* go on with the call chain */
887         ret = ldb_next_request(module, down_req);
888
889         /* do not free down_req as the call results may be linked to it,
890          * it will be freed when the upper level request get freed */
891         if (ret == LDB_SUCCESS) {
892                 req->async.handle = down_req->async.handle;
893         }
894
895         return ret;
896 }
897
898 static int samldb_destructor(void *module_ctx)
899 {
900         /* struct ldb_module *ctx = module_ctx; */
901         /* put your clean-up functions here */
902         return 0;
903 }
904
905 static int samldb_request(struct ldb_module *module, struct ldb_request *req)
906 {
907         switch (req->operation) {
908
909         case LDB_REQ_ADD:
910                 return samldb_add(module, req);
911
912         case LDB_ASYNC_ADD:
913                 return samldb_add_async(module, req);
914
915         default:
916                 return ldb_next_request(module, req);
917
918         }
919 }
920
921 static int samldb_init(struct ldb_module *module)
922 {
923         talloc_set_destructor(module, samldb_destructor);
924         return ldb_next_init(module);
925 }
926
927 static const struct ldb_module_ops samldb_ops = {
928         .name          = "samldb",
929         .init_context  = samldb_init,
930         .request       = samldb_request
931 };
932
933
934 int samldb_module_init(void)
935 {
936         return ldb_register_module(&samldb_ops);
937 }