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