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