r16061: Prove that removing the objectClass list in the samldb module breaks things.
[ira/wip.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 LDB_ERR_OPERATIONS_ERROR;
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 LDB_ERR_OPERATIONS_ERROR;
212         }
213
214         *old_rid = strtol(str, NULL, 0);
215         talloc_free(res);
216         return LDB_SUCCESS;
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         ret = samldb_find_next_rid(module, mem_ctx, dn, &old_rid);      
230         if (ret) {
231                 return ret;
232         }
233                 
234         /* return the new object sid */
235         obj_sid = dom_sid_add_rid(mem_ctx, dom_sid, old_rid);
236                 
237         ret = samldb_set_next_rid(module->ldb, mem_ctx, dn, old_rid, old_rid + 1);
238         if (ret != 0) {
239                 return ret;
240         }
241
242         *new_sid = dom_sid_add_rid(mem_ctx, dom_sid, old_rid + 1);
243         if (!*new_sid) {
244                 return LDB_ERR_OPERATIONS_ERROR;
245         }
246
247         ret = gendb_search(module->ldb,
248                            mem_ctx, NULL, &sid_msgs, sid_attrs,
249                            "objectSid=%s",
250                            ldap_encode_ndr_dom_sid(mem_ctx, *new_sid));
251         if (ret == -1) {
252                 /* Bugger, there is a problem, and we don't know what it is until gendb_search improves */
253                 return LDB_ERR_OPERATIONS_ERROR;
254         } else if (ret != 0) {
255                 /* gah, there are conflicting sids.
256                  * This is a critical situation it means that someone messed up with
257                  * the DB and nextRid is not returning free RIDs, report an error
258                  * and refuse to create any user until the problem is fixed */
259                 ldb_set_errstring(module->ldb, talloc_asprintf(mem_ctx, "Critical Error: unconsistent DB, unable to retireve an unique RID to generate a new SID"));
260                 return LDB_ERR_OPERATIONS_ERROR;
261         }
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 LDB_ERR_OPERATIONS_ERROR;
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 LDB_SUCCESS;
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 LDB_ERR_OPERATIONS_ERROR;
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 LDB_ERR_OPERATIONS_ERROR;
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 = LDB_SUCCESS;
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 == LDB_SUCCESS) {
591                 talloc_steal(msg, msg2);
592                 *ret_msg = msg2;
593         }
594         talloc_free(mem_ctx);
595         return ret;
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
620                 ret = samldb_copy_template(module, msg2, "(&(CN=TemplateComputer)(objectclass=userTemplate))");
621                 if (ret) {
622                         ldb_debug(module->ldb, LDB_DEBUG_WARNING, "samldb_fill_user_or_computer_object: Error copying computer template!\n");
623                         talloc_free(mem_ctx);
624                         return ret;
625                 }
626
627                 /* readd user and then computer objectclasses */
628                 if ( ! samldb_find_or_add_value(module, msg2, "objectclass", "user", "user")) {
629                         talloc_free(mem_ctx);
630                         return LDB_ERR_OPERATIONS_ERROR;
631                 }
632                 if ( ! samldb_find_or_add_value(module, msg2, "objectclass", "computer", "computer")) {
633                         talloc_free(mem_ctx);
634                         return LDB_ERR_OPERATIONS_ERROR;
635                 }
636                 
637         } else {
638                 ret = samldb_copy_template(module, msg2, "(&(CN=TemplateUser)(objectclass=userTemplate))");
639                 if (ret) {
640                         ldb_debug(module->ldb, LDB_DEBUG_WARNING, "samldb_fill_user_or_computer_object: Error copying user template!\n");
641                         talloc_free(mem_ctx);
642                         return ret;
643                 }
644                 /* readd user objectclass */
645                 if ( ! samldb_find_or_add_value(module, msg2, "objectclass", "user", "user")) {
646                         talloc_free(mem_ctx);
647                         return LDB_ERR_OPERATIONS_ERROR;
648                 }
649         }
650
651         rdn = ldb_dn_get_rdn(msg2, msg2->dn);
652
653         if (strcasecmp(rdn->name, "cn") != 0) {
654                 ldb_set_errstring(module->ldb, talloc_asprintf(module, "Bad RDN (%s=) for user/computer, should be CN=!\n", rdn->name));
655                 talloc_free(mem_ctx);
656                 return LDB_ERR_CONSTRAINT_VIOLATION;
657         }
658
659         if (ldb_msg_find_element(msg2, "samAccountName") == NULL) {
660                 name = samldb_generate_samAccountName(module, mem_ctx);
661                 if (!name) {
662                         talloc_free(mem_ctx);
663                         return LDB_ERR_OPERATIONS_ERROR;
664                 }
665                 if ( ! samldb_find_or_add_attribute(module, msg2, "sAMAccountName", name)) {
666                         talloc_free(mem_ctx);
667                         return LDB_ERR_OPERATIONS_ERROR;
668                 }
669         }
670
671         /*
672           TODO: useraccountcontrol: setting value 0 gives 0x200 for users
673         */
674
675         /* Manage SID allocation, conflicts etc */
676         ret = samldb_handle_sid(module, mem_ctx, msg2); 
677
678         /* TODO: objectCategory, userAccountControl, badPwdCount, codePage, countryCode, badPasswordTime, lastLogoff, lastLogon, pwdLastSet, primaryGroupID, accountExpires, logonCount */
679
680         if (ret == 0) {
681                 *ret_msg = msg2;
682                 talloc_steal(msg, msg2);
683         }
684         talloc_free(mem_ctx);
685         return ret;
686 }
687         
688 static int samldb_fill_foreignSecurityPrincipal_object(struct ldb_module *module, const struct ldb_message *msg, 
689                                                                        struct ldb_message **ret_msg)
690 {
691         struct ldb_message *msg2;
692         struct ldb_dn_component *rdn;
693         struct dom_sid *dom_sid;
694         struct dom_sid *sid;
695         const char *dom_attrs[] = { "name", NULL };
696         struct ldb_message **dom_msgs;
697         int ret;
698
699         TALLOC_CTX *mem_ctx = talloc_new(msg);
700         if (!mem_ctx) {
701                 return LDB_ERR_OPERATIONS_ERROR;
702         }
703
704         /* build the new msg */
705         msg2 = ldb_msg_copy(mem_ctx, msg);
706         if (!msg2) {
707                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_foreignSecurityPrincpal_object: ldb_msg_copy failed!\n");
708                 talloc_free(mem_ctx);
709                 return LDB_ERR_OPERATIONS_ERROR;
710         }
711
712         ret = samldb_copy_template(module, msg2, "(&(CN=TemplateForeignSecurityPrincipal)(objectclass=foreignSecurityPrincipalTemplate))");
713         if (ret != 0) {
714                 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "samldb_fill_foreignSecurityPrincipal_object: Error copying template!\n");
715                 talloc_free(mem_ctx);
716                 return ret;
717         }
718
719         rdn = ldb_dn_get_rdn(msg2, msg2->dn);
720
721         if (strcasecmp(rdn->name, "cn") != 0) {
722                 ldb_set_errstring(module->ldb, talloc_asprintf(module, "Bad RDN (%s=) for ForeignSecurityPrincipal, should be CN=!", rdn->name));
723                 talloc_free(mem_ctx);
724                 return LDB_ERR_CONSTRAINT_VIOLATION;
725         }
726
727         /* Slightly different for the foreign sids.  We don't want
728          * domain SIDs ending up there, it would cause all sorts of
729          * pain */
730
731         sid = dom_sid_parse_talloc(msg2, (const char *)rdn->value.data);
732         if (!sid) {
733                 ldb_set_errstring(module->ldb, talloc_asprintf(module, "No valid found SID in ForeignSecurityPrincipal CN!"));
734                 talloc_free(mem_ctx);
735                 return LDB_ERR_CONSTRAINT_VIOLATION;
736         }
737
738         if ( ! samldb_msg_add_sid(module, msg2, "objectSid", sid)) {
739                 talloc_free(sid);
740                 return LDB_ERR_OPERATIONS_ERROR;
741         }
742
743         dom_sid = dom_sid_dup(mem_ctx, sid);
744         if (!dom_sid) {
745                 talloc_free(mem_ctx);
746                 return LDB_ERR_OPERATIONS_ERROR;
747         }
748         /* get the domain component part of the provided SID */
749         dom_sid->num_auths--;
750
751         /* find the domain DN */
752
753         ret = gendb_search(module->ldb,
754                            mem_ctx, NULL, &dom_msgs, dom_attrs,
755                            "(&(objectSid=%s)(objectclass=domain))",
756                            ldap_encode_ndr_dom_sid(mem_ctx, dom_sid));
757         if (ret >= 1) {
758                 const char *name = samdb_result_string(dom_msgs[0], "name", NULL);
759                 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)); 
760                 /* We don't really like the idea of foreign sids that are not foreign */
761                 return LDB_ERR_CONSTRAINT_VIOLATION;
762         } else if (ret == -1) {
763                 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));
764                 talloc_free(dom_msgs);
765                 return -1;
766         }
767
768         /* This isn't an operation on a domain we know about, so just
769          * check for the SID, looking for duplicates via the common
770          * code */
771         ret = samldb_notice_sid(module, msg2, sid);
772         if (ret == 0) {
773                 talloc_steal(msg, msg2);
774                 *ret_msg = msg2;
775         }
776         
777         return ret;
778 }
779
780 /* add_record */
781
782 /*
783  * FIXME
784  *
785  * Actually this module is not async at all as it does a number of sync searches
786  * in the process. It still to be decided how to deal with it properly so it is
787  * left SYNC for now until we think of a good solution.
788  */
789
790 static int samldb_add(struct ldb_module *module, struct ldb_request *req)
791 {
792         const struct ldb_message *msg = req->op.add.message;
793         struct ldb_message *msg2 = NULL;
794         struct ldb_request *down_req;
795         int ret;
796
797         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "samldb_add_record\n");
798
799         if (ldb_dn_is_special(msg->dn)) { /* do not manipulate our control entries */
800                 return ldb_next_request(module, req);
801         }
802
803         /* is user or computer? */
804         if ((samldb_find_attribute(msg, "objectclass", "user") != NULL) ||
805             (samldb_find_attribute(msg, "objectclass", "computer") != NULL)) {
806                 /*  add all relevant missing objects */
807                 ret = samldb_fill_user_or_computer_object(module, msg, &msg2);
808                 if (ret) {
809                         return ret;
810                 }
811         }
812
813         /* is group? add all relevant missing objects */
814         if ( ! msg2 ) {
815                 if (samldb_find_attribute(msg, "objectclass", "group") != NULL) {
816                         ret = samldb_fill_group_object(module, msg, &msg2);
817                         if (ret) {
818                                 return ret;
819                         }
820                 }
821         }
822
823         /* perhaps a foreignSecurityPrincipal? */
824         if ( ! msg2 ) {
825                 if (samldb_find_attribute(msg, "objectclass", "foreignSecurityPrincipal") != NULL) {
826                         ret = samldb_fill_foreignSecurityPrincipal_object(module, msg, &msg2);
827                         if (ret) {
828                                 return ret;
829                         }
830                 }
831         }
832
833         if (msg2 == NULL) {
834                 return ldb_next_request(module, req);
835         }
836
837         down_req = talloc(module, struct ldb_request);
838         if (down_req == NULL) {
839                 return LDB_ERR_OPERATIONS_ERROR;
840         }
841
842         *down_req = *req;
843         
844         down_req->op.add.message = talloc_steal(down_req, msg2);
845
846         ldb_set_timeout_from_prev_req(module->ldb, req, down_req);
847
848         /* go on with the call chain */
849         ret = ldb_next_request(module, down_req);
850
851         /* do not free down_req as the call results may be linked to it,
852          * it will be freed when the upper level request get freed */
853         if (ret == LDB_SUCCESS) {
854                 req->async.handle = down_req->async.handle;
855         }
856
857         return ret;
858 }
859
860 static int samldb_destructor(void *module_ctx)
861 {
862         /* struct ldb_module *ctx = module_ctx; */
863         /* put your clean-up functions here */
864         return 0;
865 }
866
867 static int samldb_init(struct ldb_module *module)
868 {
869         talloc_set_destructor(module, samldb_destructor);
870         return ldb_next_init(module);
871 }
872
873 static const struct ldb_module_ops samldb_ops = {
874         .name          = "samldb",
875         .init_context  = samldb_init,
876         .add           = samldb_add,
877 };
878
879
880 int samldb_module_init(void)
881 {
882         return ldb_register_module(&samldb_ops);
883 }