r12427: Move SAMR CreateUser2 to transactions, and re-add support for
[samba.git] / source / dsdb / samdb / ldb_modules / samldb.c
1 /* 
2    SAM ldb module
3
4    Copyright (C) Simo Sorce  2004
5
6    * NOTICE: this module is NOT released under the GNU LGPL license as
7    * other ldb code. This module is release under the GNU GPL v2 or
8    * later license.
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 /*
26  *  Name: ldb
27  *
28  *  Component: ldb samldb module
29  *
30  *  Description: add embedded user/group creation functionality
31  *
32  *  Author: Simo Sorce
33  */
34
35 #include "includes.h"
36 #include "lib/ldb/include/ldb.h"
37 #include "lib/ldb/include/ldb_errors.h"
38 #include "lib/ldb/include/ldb_private.h"
39 #include "system/time.h"
40 #include "librpc/gen_ndr/ndr_security.h"
41
42 #define SAM_ACCOUNT_NAME_BASE "$000000-000000000000"
43
44 /*
45   allocate a new id, attempting to do it atomically
46   return 0 on failure, the id on success
47 */
48 static int samldb_allocate_next_rid(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
49                                    const struct ldb_dn *dn, uint32_t *id)
50 {
51         const char * const attrs[2] = { "nextRid", NULL };
52         struct ldb_result *res = NULL;
53         struct ldb_message msg;
54         int ret;
55         const char *str;
56         struct ldb_val vals[2];
57         struct ldb_message_element els[2];
58
59         ret = ldb_search(ldb, dn, LDB_SCOPE_BASE, "nextRid=*", attrs, &res);
60         if (ret != LDB_SUCCESS || res->count != 1) {
61                 if (res) talloc_free(res);
62                 return -1;
63         }
64         str = ldb_msg_find_string(res->msgs[0], "nextRid", NULL);
65         if (str == NULL) {
66                 ldb_debug(ldb, LDB_DEBUG_FATAL, "attribute nextRid not found in %s\n", ldb_dn_linearize(res, dn));
67                 talloc_free(res);
68                 return -1;
69         }
70
71         *id = strtol(str, NULL, 0);
72         if ((*id)+1 == 0) {
73                 /* out of IDs ! */
74                 ldb_debug(ldb, LDB_DEBUG_FATAL, "Are we out of valid IDs ?\n");
75                 talloc_free(res);
76                 return -1;
77         }
78         talloc_free(res);
79
80         /* we do a delete and add as a single operation. That prevents
81            a race */
82         ZERO_STRUCT(msg);
83         msg.dn = ldb_dn_copy(mem_ctx, dn);
84         if (!msg.dn) {
85                 return -1;
86         }
87         msg.num_elements = 2;
88         msg.elements = els;
89
90         els[0].num_values = 1;
91         els[0].values = &vals[0];
92         els[0].flags = LDB_FLAG_MOD_DELETE;
93         els[0].name = talloc_strdup(mem_ctx, "nextRid");
94         if (!els[0].name) {
95                 return -1;
96         }
97
98         els[1].num_values = 1;
99         els[1].values = &vals[1];
100         els[1].flags = LDB_FLAG_MOD_ADD;
101         els[1].name = els[0].name;
102
103         vals[0].data = (uint8_t *)talloc_asprintf(mem_ctx, "%u", *id);
104         if (!vals[0].data) {
105                 return -1;
106         }
107         vals[0].length = strlen((char *)vals[0].data);
108
109         vals[1].data = (uint8_t *)talloc_asprintf(mem_ctx, "%u", (*id)+1);
110         if (!vals[1].data) {
111                 return -1;
112         }
113         vals[1].length = strlen((char *)vals[1].data);
114
115         ret = ldb_modify(ldb, &msg);
116         if (ret != 0) {
117                 return 1;
118         }
119
120         (*id)++;
121
122         return 0;
123 }
124
125 static struct ldb_dn *samldb_search_domain(struct ldb_module *module, TALLOC_CTX *mem_ctx, const struct ldb_dn *dn)
126 {
127         TALLOC_CTX *local_ctx;
128         struct ldb_dn *sdn;
129         struct ldb_result *res = NULL;
130         int ret = 0;
131
132         local_ctx = talloc_new(mem_ctx);
133         if (local_ctx == NULL) return NULL;
134
135         sdn = ldb_dn_copy(local_ctx, dn);
136         do {
137                 ret = ldb_search(module->ldb, sdn, LDB_SCOPE_BASE, "objectClass=domain", NULL, &res);
138                 talloc_steal(local_ctx, res);
139                 if (ret == LDB_SUCCESS && res->count == 1)
140                         break;
141         } while ((sdn = ldb_dn_get_parent(local_ctx, sdn)));
142
143         if (ret != LDB_SUCCESS || res->count != 1) {
144                 talloc_free(local_ctx);
145                 return NULL;
146         }
147
148         talloc_steal(mem_ctx, sdn);
149         talloc_free(local_ctx);
150
151         return sdn;
152 }
153
154 /* search the domain related to the provided dn
155    allocate a new RID for the domain
156    return the new sid string
157 */
158 static struct dom_sid *samldb_get_new_sid(struct ldb_module *module, 
159                                           TALLOC_CTX *mem_ctx, const struct ldb_dn *obj_dn)
160 {
161         const char * const attrs[2] = { "objectSid", NULL };
162         struct ldb_result *res = NULL;
163         const struct ldb_dn *dom_dn;
164         uint32_t rid;
165         int ret;
166         struct dom_sid *dom_sid, *obj_sid;
167
168         /* get the domain component part of the provided dn */
169
170         /* FIXME: quick search here, I think we should use something like
171            ldap_parse_dn here to be 100% sure we get the right domain dn */
172
173         /* FIXME: "dc=" is probably not utf8 safe either,
174            we need a multibyte safe substring search function here */
175         
176         dom_dn = samldb_search_domain(module, mem_ctx, obj_dn);
177         if (dom_dn == NULL) {
178                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Invalid dn (%s) not child of a domain object!\n", ldb_dn_linearize(mem_ctx, obj_dn));
179                 return NULL;
180         }
181
182         /* find the domain sid */
183
184         ret = ldb_search(module->ldb, dom_dn, LDB_SCOPE_BASE, "objectSid=*", attrs, &res);
185         if (ret != LDB_SUCCESS || res->count != 1) {
186                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_get_new_sid: error retrieving domain sid!\n");
187                 talloc_free(res);
188                 return NULL;
189         }
190
191         dom_sid = samdb_result_dom_sid(res, res->msgs[0], "objectSid");
192         if (dom_sid == NULL) {
193                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_get_new_sid: error retrieving domain sid!\n");
194                 talloc_free(res);
195                 return NULL;
196         }
197
198         /* allocate a new Rid for the domain */
199         ret = samldb_allocate_next_rid(module->ldb, mem_ctx, dom_dn, &rid);
200         if (ret != 0) {
201                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Failed to increment nextRid of %s\n", ldb_dn_linearize(mem_ctx, dom_dn));
202                 talloc_free(res);
203                 return NULL;
204         }
205
206         /* return the new object sid */
207         obj_sid = dom_sid_add_rid(mem_ctx, dom_sid, rid);
208
209         talloc_free(res);
210
211         return obj_sid;
212 }
213
214 static char *samldb_generate_samAccountName(const void *mem_ctx) {
215         char *name;
216
217         name = talloc_strdup(mem_ctx, SAM_ACCOUNT_NAME_BASE);
218         /* TODO: randomize name */      
219
220         return name;
221 }
222
223 /* if value is not null also check for attribute to have exactly that value */
224 static struct ldb_message_element *samldb_find_attribute(const struct ldb_message *msg, const char *name, const char *value)
225 {
226         int i, j;
227
228         for (i = 0; i < msg->num_elements; i++) {
229                 if (ldb_attr_cmp(name, msg->elements[i].name) == 0) {
230                         if (!value) {
231                                 return &msg->elements[i];
232                         }
233                         for (j = 0; j < msg->elements[i].num_values; j++) {
234                                 if (strcasecmp(value, 
235                                                (char *)msg->elements[i].values[j].data) == 0) {
236                                         return &msg->elements[i];
237                                 }
238                         }
239                 }
240         }
241
242         return NULL;
243 }
244
245 static BOOL samldb_msg_add_string(struct ldb_module *module, struct ldb_message *msg, const char *name, const char *value)
246 {
247         char *aname = talloc_strdup(msg, name);
248         char *aval = talloc_strdup(msg, value);
249
250         if (aname == NULL || aval == NULL) {
251                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_msg_add_string: talloc_strdup failed!\n");
252                 return False;
253         }
254
255         if (ldb_msg_add_string(msg, aname, aval) != 0) {
256                 return False;
257         }
258
259         return True;
260 }
261
262 static BOOL samldb_msg_add_sid(struct ldb_module *module, struct ldb_message *msg, const char *name, const struct dom_sid *sid)
263 {
264         struct ldb_val v;
265         NTSTATUS status;
266         status = ndr_push_struct_blob(&v, msg, sid, 
267                                       (ndr_push_flags_fn_t)ndr_push_dom_sid);
268         if (!NT_STATUS_IS_OK(status)) {
269                 return -1;
270         }
271         return (ldb_msg_add_value(msg, name, &v) == 0);
272 }
273
274 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)
275 {
276         if (samldb_find_attribute(msg, name, value) == NULL) {
277                 return samldb_msg_add_string(module, msg, name, set_value);
278         }
279         return True;
280 }
281
282 static int samldb_copy_template(struct ldb_module *module, struct ldb_message *msg, const char *filter)
283 {
284         struct ldb_result *res;
285         struct ldb_message *t;
286         int ret, i, j;
287         
288
289         /* pull the template record */
290         ret = ldb_search(module->ldb, NULL, LDB_SCOPE_SUBTREE, filter, NULL, &res);
291         if (ret != LDB_SUCCESS || res->count != 1) {
292                 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "samldb: ERROR: template '%s' matched too many records\n", filter);
293                 return -1;
294         }
295         t = res->msgs[0];
296
297         for (i = 0; i < t->num_elements; i++) {
298                 struct ldb_message_element *el = &t->elements[i];
299                 /* some elements should not be copied from the template */
300                 if (strcasecmp(el->name, "cn") == 0 ||
301                     strcasecmp(el->name, "name") == 0 ||
302                     strcasecmp(el->name, "sAMAccountName") == 0 ||
303                     strcasecmp(el->name, "objectGUID") == 0) {
304                         continue;
305                 }
306                 for (j = 0; j < el->num_values; j++) {
307                         if (strcasecmp(el->name, "objectClass") == 0 &&
308                             (strcasecmp((char *)el->values[j].data, "Template") == 0 ||
309                              strcasecmp((char *)el->values[j].data, "userTemplate") == 0 ||
310                              strcasecmp((char *)el->values[j].data, "groupTemplate") == 0 ||
311                              strcasecmp((char *)el->values[j].data, "foreignSecurityPrincipalTemplate") == 0 ||
312                              strcasecmp((char *)el->values[j].data, "aliasTemplate") == 0 || 
313                              strcasecmp((char *)el->values[j].data, "trustedDomainTemplate") == 0 || 
314                              strcasecmp((char *)el->values[j].data, "secretTemplate") == 0)) {
315                                 continue;
316                         }
317                         if ( ! samldb_find_or_add_attribute(module, msg, el->name, 
318                                                             NULL,
319                                                             (char *)el->values[j].data)) {
320                                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Attribute adding failed...\n");
321                                 talloc_free(res);
322                                 return -1;
323                         }
324                 }
325         }
326
327         talloc_free(res);
328
329         return 0;
330 }
331
332 static struct ldb_message *samldb_fill_group_object(struct ldb_module *module, const struct ldb_message *msg)
333 {
334         struct ldb_message *msg2;
335         struct ldb_message_element *attribute;
336         struct ldb_dn_component *rdn;
337
338         if (samldb_find_attribute(msg, "objectclass", "group") == NULL) {
339                 return NULL;
340         }
341
342         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "samldb_fill_group_object\n");
343
344         /* build the new msg */
345         msg2 = ldb_msg_copy(module->ldb, msg);
346         if (!msg2) {
347                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_group_object: ldb_msg_copy failed!\n");
348                 return NULL;
349         }
350
351         if (samldb_copy_template(module, msg2, "(&(CN=TemplateGroup)(objectclass=groupTemplate))") != 0) {
352                 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "samldb_fill_group_object: Error copying template!\n");
353                 return NULL;
354         }
355
356         if ((rdn = ldb_dn_get_rdn(msg2, msg2->dn)) == NULL) {
357                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_group_object: Bad DN (%s)!\n", ldb_dn_linearize(msg2, msg2->dn));
358                 return NULL;
359         }
360         if (strcasecmp(rdn->name, "cn") != 0) {
361                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_group_object: Bad RDN (%s) for group!\n", rdn->name);
362                 return NULL;
363         }
364
365         if ((attribute = samldb_find_attribute(msg2, "objectSid", NULL)) == NULL ) {
366                 struct dom_sid *sid = samldb_get_new_sid(module, msg2, msg2->dn);
367                 if (sid == NULL) {
368                         ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_group_object: internal error! Can't generate new sid\n");
369                         return NULL;
370                 }
371
372                 if (!samldb_msg_add_sid(module, msg2, "objectSid", sid)) {
373                         talloc_free(sid);
374                         return NULL;
375                 }
376                 talloc_free(sid);
377         }
378
379         if ( ! samldb_find_or_add_attribute(module, msg2, "sAMAccountName", NULL, samldb_generate_samAccountName(msg2))) {
380                 return NULL;
381         }
382
383         talloc_steal(msg, msg2);
384
385         return msg2;
386 }
387
388 static struct ldb_message *samldb_fill_user_or_computer_object(struct ldb_module *module, const struct ldb_message *msg)
389 {
390         struct ldb_message *msg2;
391         struct ldb_message_element *attribute;
392         struct ldb_dn_component *rdn;
393
394         if ((samldb_find_attribute(msg, "objectclass", "user") == NULL) && 
395             (samldb_find_attribute(msg, "objectclass", "computer") == NULL)) {
396                 return NULL;
397         }
398
399         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "samldb_fill_user_or_computer_object\n");
400
401         /* build the new msg */
402         msg2 = ldb_msg_copy(module->ldb, msg);
403         if (!msg2) {
404                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_group_object: ldb_msg_copy failed!\n");
405                 return NULL;
406         }
407
408         if (samldb_find_attribute(msg, "objectclass", "computer") != NULL) {
409                 if (samldb_copy_template(module, msg2, "(&(CN=TemplateServer)(objectclass=userTemplate))") != 0) {
410                         ldb_debug(module->ldb, LDB_DEBUG_WARNING, "samldb_fill_user_or_computer_object: Error copying computer template!\n");
411                         return NULL;
412                 }
413         } else {
414                 if (samldb_copy_template(module, msg2, "(&(CN=TemplateUser)(objectclass=userTemplate))") != 0) {
415                         ldb_debug(module->ldb, LDB_DEBUG_WARNING, "samldb_fill_user_or_computer_object: Error copying user template!\n");
416                         return NULL;
417                 }
418         }
419
420         if ((rdn = ldb_dn_get_rdn(msg2, msg2->dn)) == NULL) {
421                 return NULL;
422         }
423         if (strcasecmp(rdn->name, "cn") != 0) {
424                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_user_or_computer_object: Bad RDN (%s) for user/computer!\n", rdn->name);
425                 return NULL;
426         }
427
428         /* if the only attribute was: "objectclass: computer", then make sure we also add "user" objectclass */
429         if ( ! samldb_find_or_add_attribute(module, msg2, "objectclass", "user", "user")) {
430                 return NULL;
431         }
432
433         if ((attribute = samldb_find_attribute(msg2, "objectSid", NULL)) == NULL ) {
434                 struct dom_sid *sid;
435                 sid = samldb_get_new_sid(module, msg2, msg2->dn);
436                 if (sid == NULL) {
437                         ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_user_or_computer_object: internal error! Can't generate new sid\n");
438                         return NULL;
439                 }
440
441                 if ( ! samldb_msg_add_sid(module, msg2, "objectSid", sid)) {
442                         talloc_free(sid);
443                         return NULL;
444                 }
445                 talloc_free(sid);
446         }
447
448         if ( ! samldb_find_or_add_attribute(module, msg2, "sAMAccountName", NULL, samldb_generate_samAccountName(msg2))) {
449                 return NULL;
450         }
451
452         /*
453           useraccountcontrol: setting value 0 gives 0x200 for users
454         */
455
456         /* TODO: objectCategory, userAccountControl, badPwdCount, codePage, countryCode, badPasswordTime, lastLogoff, lastLogon, pwdLastSet, primaryGroupID, accountExpires, logonCount */
457
458         return msg2;
459 }
460
461 static struct ldb_message *samldb_fill_foreignSecurityPrincipal_object(struct ldb_module *module, const struct ldb_message *msg)
462 {
463         struct ldb_message *msg2;
464         struct ldb_message_element *attribute;
465         struct ldb_dn_component *rdn;
466
467         if (samldb_find_attribute(msg, "objectclass", "foreignSecurityPrincipal") == NULL) {
468                 return NULL;
469         }
470
471         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "samldb_fill_foreignSecurityPrincipal_object\n");
472
473         /* build the new msg */
474         msg2 = ldb_msg_copy(module->ldb, msg);
475         if (!msg2) {
476                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_foreignSecurityPrincpal_object: ldb_msg_copy failed!\n");
477                 return NULL;
478         }
479
480         talloc_steal(msg, msg2);
481
482         if (samldb_copy_template(module, msg2, "(&(CN=TemplateForeignSecurityPrincipal)(objectclass=foreignSecurityPrincipalTemplate))") != 0) {
483                 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "samldb_fill_foreignSecurityPrincipal_object: Error copying template!\n");
484                 return NULL;
485         }
486
487         if ((rdn = ldb_dn_get_rdn(msg2, msg2->dn)) == NULL) {
488                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_foreignSecurityPrincipal_object: Bad DN (%s)!\n", ldb_dn_linearize(msg2, msg2->dn));
489                 return NULL;
490         }
491         if (strcasecmp(rdn->name, "cn") != 0) {
492                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_foreignSecurityPrincipal_object: Bad RDN (%s) for foreignSecurityPrincpal!\n", rdn->name);
493                 return NULL;
494         }
495
496         if ((attribute = samldb_find_attribute(msg2, "objectSid", NULL)) == NULL ) {
497                 struct dom_sid *sid = dom_sid_parse_talloc(msg2, (char *)rdn->value.data);
498                 if (sid == NULL) {
499                         ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_foreignSecurityPrincipal_object: internal error! Can't parse sid in CN\n");
500                         return NULL;
501                 }
502
503                 if (!samldb_msg_add_sid(module, msg2, "objectSid", sid)) {
504                         talloc_free(sid);
505                         return NULL;
506                 }
507                 talloc_free(sid);
508         }
509
510         return msg2;
511 }
512
513 /* add_record */
514 static int samldb_add(struct ldb_module *module, struct ldb_request *req)
515 {
516         const struct ldb_message *msg = req->op.add.message;
517         struct ldb_message *msg2 = NULL;
518         int ret;
519
520         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "samldb_add_record\n");
521
522         
523         if (ldb_dn_is_special(msg->dn)) { /* do not manipulate our control entries */
524                 return ldb_next_request(module, req);
525         }
526
527         /* is user or computer?  add all relevant missing objects */
528         msg2 = samldb_fill_user_or_computer_object(module, msg);
529
530         /* is group? add all relevant missing objects */
531         if ( ! msg2 ) {
532                 msg2 = samldb_fill_group_object(module, msg);
533         }
534
535         /* perhaps a foreignSecurityPrincipal? */
536         if ( ! msg2 ) {
537                 msg2 = samldb_fill_foreignSecurityPrincipal_object(module, msg);
538         }
539
540         if (msg2) {
541                 req->op.add.message = msg2;
542                 ret = ldb_next_request(module, req);
543                 req->op.add.message = msg;
544         } else {
545                 ret = ldb_next_request(module, req);
546         }
547
548         return ret;
549 }
550
551 static int samldb_destructor(void *module_ctx)
552 {
553         /* struct ldb_module *ctx = module_ctx; */
554         /* put your clean-up functions here */
555         return 0;
556 }
557
558 static int samldb_request(struct ldb_module *module, struct ldb_request *req)
559 {
560         switch (req->operation) {
561
562         case LDB_REQ_ADD:
563                 return samldb_add(module, req);
564
565         default:
566                 return ldb_next_request(module, req);
567
568         }
569 }
570
571 static const struct ldb_module_ops samldb_ops = {
572         .name          = "samldb",
573         .request       = samldb_request
574 };
575
576
577 /* the init function */
578 #ifdef HAVE_DLOPEN_DISABLED
579  struct ldb_module *init_module(struct ldb_context *ldb, const char *options[])
580 #else
581 struct ldb_module *samldb_module_init(struct ldb_context *ldb, const char *options[])
582 #endif
583 {
584         struct ldb_module *ctx;
585
586         ctx = talloc(ldb, struct ldb_module);
587         if (!ctx)
588                 return NULL;
589
590         ctx->private_data = NULL;
591         ctx->ldb = ldb;
592         ctx->prev = ctx->next = NULL;
593         ctx->ops = &samldb_ops;
594
595         talloc_set_destructor(ctx, samldb_destructor);
596
597         return ctx;
598 }