r6470: Remove ldb_search_free() it is not needed anymore.
[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_private.h"
38 #include <time.h>
39
40 #define SAM_ACCOUNT_NAME_BASE "$000000-000000000000"
41
42 struct private_data {
43         const char *error_string;
44 };
45
46 static int samldb_search(struct ldb_module *module, const char *base,
47                                   enum ldb_scope scope, const char *expression,
48                                   const char * const *attrs, struct ldb_message ***res)
49 {
50         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "samldb_search\n");
51         return ldb_next_search(module, base, scope, expression, attrs, res);
52 }
53
54 /*
55   allocate a new id, attempting to do it atomically
56   return 0 on failure, the id on success
57 */
58 static int samldb_allocate_next_rid(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
59                                    const char *dn, uint32_t *id)
60 {
61         const char * const attrs[2] = { "nextRid", NULL };
62         struct ldb_message **res = NULL;
63         struct ldb_message msg;
64         int ret;
65         const char *str;
66         struct ldb_val vals[2];
67         struct ldb_message_element els[2];
68
69         ret = ldb_search(ldb, dn, LDB_SCOPE_BASE, "nextRid=*", attrs, &res);
70         if (ret != 1) {
71                 if (res) talloc_free(res);
72                 return -1;
73         }
74         str = ldb_msg_find_string(res[0], "nextRid", NULL);
75         if (str == NULL) {
76                 ldb_debug(ldb, LDB_DEBUG_FATAL, "attribute nextRid not found in %s\n", dn);
77                 talloc_free(res);
78                 return -1;
79         }
80
81         *id = strtol(str, NULL, 0);
82         if ((*id)+1 == 0) {
83                 /* out of IDs ! */
84                 ldb_debug(ldb, LDB_DEBUG_FATAL, "Are we out of valid IDs ?\n");
85                 talloc_free(res);
86                 return -1;
87         }
88         talloc_free(res);
89
90         /* we do a delete and add as a single operation. That prevents
91            a race */
92         ZERO_STRUCT(msg);
93         msg.dn = talloc_strdup(mem_ctx, dn);
94         if (!msg.dn) {
95                 return -1;
96         }
97         msg.num_elements = 2;
98         msg.elements = els;
99
100         els[0].num_values = 1;
101         els[0].values = &vals[0];
102         els[0].flags = LDB_FLAG_MOD_DELETE;
103         els[0].name = talloc_strdup(mem_ctx, "nextRid");
104         if (!els[0].name) {
105                 return -1;
106         }
107
108         els[1].num_values = 1;
109         els[1].values = &vals[1];
110         els[1].flags = LDB_FLAG_MOD_ADD;
111         els[1].name = els[0].name;
112
113         vals[0].data = talloc_asprintf(mem_ctx, "%u", *id);
114         if (!vals[0].data) {
115                 return -1;
116         }
117         vals[0].length = strlen(vals[0].data);
118
119         vals[1].data = talloc_asprintf(mem_ctx, "%u", (*id)+1);
120         if (!vals[1].data) {
121                 return -1;
122         }
123         vals[1].length = strlen(vals[1].data);
124
125         ret = ldb_modify(ldb, &msg);
126         if (ret != 0) {
127                 return 1;
128         }
129
130         (*id)++;
131
132         return 0;
133 }
134
135 static char *samldb_search_domain(struct ldb_module *module, TALLOC_CTX *mem_ctx, const char *dn)
136 {
137         const char *sdn;
138         struct ldb_message **res = NULL;
139         int ret;
140
141         sdn = dn;
142         while ((sdn = strchr(sdn, ',')) != NULL) {
143
144                 sdn++;
145
146                 ret = ldb_search(module->ldb, sdn, LDB_SCOPE_BASE, "objectClass=domain", NULL, &res);
147                 talloc_free(res);
148
149                 if (ret == 1)
150                         break;
151         }
152
153         if (ret != 1) {
154                 return NULL;
155         }
156
157         return talloc_strdup(mem_ctx, sdn);
158 }
159
160 /* search the domain related to the provided dn
161    allocate a new RID for the domain
162    return the new sid string
163 */
164 static char *samldb_get_new_sid(struct ldb_module *module, TALLOC_CTX *mem_ctx, const char *obj_dn)
165 {
166         const char * const attrs[2] = { "objectSid", NULL };
167         struct ldb_message **res = NULL;
168         const char *dom_dn, *dom_sid;
169         char *obj_sid;
170         uint32_t rid;
171         int ret, tries = 10;
172
173         /* get the domain component part of the provided dn */
174
175         /* FIXME: quick search here, I think we should use something like
176            ldap_parse_dn here to be 100% sure we get the right domain dn */
177
178         /* FIXME: "dc=" is probably not utf8 safe either,
179            we need a multibyte safe substring search function here */
180         
181         dom_dn = samldb_search_domain(module, mem_ctx, obj_dn);
182         if (dom_dn == NULL) {
183                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Invalid dn (%s) not child of a domain object!\n", obj_dn);
184                 return NULL;
185         }
186
187         /* find the domain sid */
188
189         ret = ldb_search(module->ldb, dom_dn, LDB_SCOPE_BASE, "objectSid=*", attrs, &res);
190         if (ret != 1) {
191                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_get_new_sid: error retrieving domain sid!\n");
192                 if (res) talloc_free(res);
193                 return NULL;
194         }
195
196         dom_sid = ldb_msg_find_string(res[0], "objectSid", NULL);
197         if (dom_sid == NULL) {
198                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_get_new_sid: error retrieving domain sid!\n");
199                 talloc_free(res);
200                 return NULL;
201         }
202
203         /* allocate a new Rid for the domain */
204
205         /* we need to try multiple times to cope with two account
206            creations at the same time */
207         while (tries--) {
208                 ret = samldb_allocate_next_rid(module->ldb, mem_ctx, dom_dn, &rid);
209                 if (ret != 1) {
210                         break;
211                 }
212         }
213         if (ret != 0) {
214                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Failed to increment nextRid of %s\n", dom_dn);
215                 talloc_free(res);
216                 return NULL;
217         }
218
219         /* return the new object sid */
220
221         obj_sid = talloc_asprintf(mem_ctx, "%s-%u", dom_sid, rid);
222
223         talloc_free(res);
224
225
226         return obj_sid;
227 }
228
229 static char *samldb_generate_samAccountName(const void *mem_ctx) {
230         char *name;
231
232         name = talloc_strdup(mem_ctx, SAM_ACCOUNT_NAME_BASE);
233         /* TODO: randomize name */      
234
235         return name;
236 }
237
238 static BOOL samldb_get_rdn_and_basedn(const void *mem_ctx, const char *dn, char **rdn, char **basedn)
239 {
240         char *p;
241
242         p = strchr(dn, ',');
243         if ( ! p ) {
244                 return False;
245         }
246
247         *rdn = talloc_strndup(mem_ctx, dn, p - dn);
248
249         if ( ! *rdn) {
250                 return False;
251         }
252
253         *basedn = talloc_strdup(mem_ctx, p + 1);
254
255         if ( ! *basedn) {
256                 talloc_free(*rdn);
257                 *rdn = NULL;
258                 return False;
259         }
260
261         return True;
262 }
263
264 /* if value is not null also check for attribute to have exactly that value */
265 static struct ldb_message_element *samldb_find_attribute(const struct ldb_message *msg, const char *name, const char *value)
266 {
267         int i, j;
268
269         for (i = 0; i < msg->num_elements; i++) {
270                 if (ldb_attr_cmp(name, msg->elements[i].name) == 0) {
271                         if (!value) {
272                                 return &msg->elements[i];
273                         }
274                         for (j = 0; j < msg->elements[i].num_values; j++) {
275                                 if (strcasecmp(value, msg->elements[i].values[j].data) == 0) {
276                                         return &msg->elements[i];
277                                 }
278                         }
279                 }
280         }
281
282         return NULL;
283 }
284
285 static BOOL samldb_msg_add_string(struct ldb_module *module, struct ldb_message *msg, const char *name, const char *value)
286 {
287         char *aname = talloc_strdup(msg, name);
288         char *aval = talloc_strdup(msg, value);
289
290         if (aname == NULL || aval == NULL) {
291                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_msg_add_string: talloc_strdup failed!\n");
292                 return False;
293         }
294
295         if (ldb_msg_add_string(module->ldb, msg, aname, aval) != 0) {
296                 return False;
297         }
298
299         return True;
300 }
301
302 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)
303 {
304         if (samldb_find_attribute(msg, name, value) == NULL) {
305                 return samldb_msg_add_string(module, msg, name, set_value);
306         }
307         return True;
308 }
309
310 static int samldb_copy_template(struct ldb_module *module, struct ldb_message *msg, const char *filter)
311 {
312         struct ldb_message **res, *t;
313         int ret, i, j;
314         
315
316         /* pull the template record */
317         ret = ldb_search(module->ldb, NULL, LDB_SCOPE_SUBTREE, filter, NULL, &res);
318         if (ret != 1) {
319                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb: ERROR: template '%s' matched %d records\n", filter, ret);
320                 return -1;
321         }
322         t = res[0];
323
324         for (i = 0; i < t->num_elements; i++) {
325                 struct ldb_message_element *el = &t->elements[i];
326                 /* some elements should not be copied from the template */
327                 if (strcasecmp(el->name, "cn") == 0 ||
328                     strcasecmp(el->name, "name") == 0 ||
329                     strcasecmp(el->name, "sAMAccountName") == 0) {
330                         continue;
331                 }
332                 for (j = 0; j < el->num_values; j++) {
333                         if (strcasecmp(el->name, "objectClass") == 0 &&
334                             (strcasecmp((char *)el->values[j].data, "Template") == 0 ||
335                              strcasecmp((char *)el->values[j].data, "userTemplate") == 0 ||
336                              strcasecmp((char *)el->values[j].data, "groupTemplate") == 0 ||
337                              strcasecmp((char *)el->values[j].data, "foreignSecurityTemplate") == 0 ||
338                              strcasecmp((char *)el->values[j].data, "aliasTemplate") == 0 || 
339                              strcasecmp((char *)el->values[j].data, "trustedDomainTemplate") == 0 || 
340                              strcasecmp((char *)el->values[j].data, "secretTemplate") == 0)) {
341                                 continue;
342                         }
343                         if ( ! samldb_find_or_add_attribute(module, msg, el->name, 
344                                                             NULL,
345                                                             (char *)el->values[j].data)) {
346                                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Attribute adding failed...\n");
347                                 talloc_free(res);
348                                 return -1;
349                         }
350                 }
351         }
352
353         talloc_free(res);
354
355         return 0;
356 }
357
358 static struct ldb_message *samldb_fill_group_object(struct ldb_module *module, const struct ldb_message *msg)
359 {
360         struct ldb_message *msg2;
361         struct ldb_message_element *attribute;
362         char *rdn, *basedn, *sidstr;
363
364         if (samldb_find_attribute(msg, "objectclass", "group") == NULL) {
365                 return NULL;
366         }
367
368         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "samldb_fill_group_object\n");
369
370         /* build the new msg */
371         msg2 = ldb_msg_copy(module->ldb, msg);
372         if (!msg2) {
373                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_group_object: ldb_msg_copy failed!\n");
374                 return NULL;
375         }
376
377         if (samldb_copy_template(module, msg2, "(&(name=TemplateGroup)(objectclass=groupTemplate))") != 0) {
378                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_group_object: Error copying template!\n");
379                 return NULL;
380         }
381
382         if ( ! samldb_get_rdn_and_basedn(msg2, msg2->dn, &rdn, &basedn)) {
383                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_group_object: Bad DN (%s)!\n", msg2->dn);
384                 return NULL;
385         }
386         if (strncasecmp(rdn, "cn", 2) != 0) {
387                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_group_object: Bad RDN (%s) for group!\n", rdn);
388                 return NULL;
389         }
390
391         if ((attribute = samldb_find_attribute(msg2, "cn", NULL)) != NULL) {
392                 if (strcasecmp(&rdn[3], attribute->values[0].data) != 0) {
393                         ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_group_object: Bad Attribute Syntax for CN\n");
394                         return NULL;
395                 }
396         } else { /* FIXME: remove this if ldb supports natively aliasing between the rdn and the "cn" attribute */
397                 if ( ! samldb_msg_add_string(module, msg2, "cn", &rdn[3])) {
398                         return NULL;
399                 }
400         }
401
402         if ((attribute = samldb_find_attribute(msg2, "name", NULL)) != NULL) {
403                 if (strcasecmp(&rdn[3], attribute->values[0].data) != 0) {
404                         return NULL;
405                 }
406         } else { /* FIXME: remove this if ldb supports natively aliasing between the rdn and the "name" attribute */
407                 if ( ! samldb_msg_add_string(module, msg2, "name", &rdn[3])) {
408                         return NULL;
409                 }
410         }
411
412         if ((attribute = samldb_find_attribute(msg2, "objectSid", NULL)) == NULL ) {
413
414                 if ((sidstr = samldb_get_new_sid(module, msg2, msg2->dn)) == NULL) {
415                         ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_group_object: internal error! Can't generate new sid\n");
416                         return NULL;
417                 }
418
419                 if ( ! samldb_msg_add_string(module, msg2, "objectSid", sidstr)) {
420                         return NULL;
421                 }
422         }
423
424         if ( ! samldb_find_or_add_attribute(module, msg2, "sAMAccountName", NULL, samldb_generate_samAccountName(msg2))) {
425                 return NULL;
426         }
427
428         /* TODO: objectGUID */
429
430         talloc_steal(msg, msg2);
431
432         return msg2;
433 }
434
435 static struct ldb_message *samldb_fill_user_or_computer_object(struct ldb_module *module, const struct ldb_message *msg)
436 {
437         struct ldb_message *msg2;
438         struct ldb_message_element *attribute;
439         char *rdn, *basedn, *sidstr;
440
441         if ((samldb_find_attribute(msg, "objectclass", "user") == NULL) && (samldb_find_attribute(msg, "objectclass", "computer") == NULL)) {
442                 return NULL;
443         }
444
445         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "samldb_fill_user_or_computer_object\n");
446
447         /* build the new msg */
448         msg2 = ldb_msg_copy(module->ldb, msg);
449         if (!msg2) {
450                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_group_object: ldb_msg_copy failed!\n");
451                 return NULL;
452         }
453
454         if (samldb_copy_template(module, msg2, "(&(name=TemplateUser)(objectclass=userTemplate))") != 0) {
455                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_user_or_computer_object: Error copying template!\n");
456                 return NULL;
457         }
458
459         if ( ! samldb_get_rdn_and_basedn(msg2, msg2->dn, &rdn, &basedn)) {
460                 return NULL;
461         }
462         if (strncasecmp(rdn, "cn", 2) != 0) {
463                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_user_or_computer_object: Bad RDN (%s) for group!\n", rdn);
464                 return NULL;
465         }
466
467         /* if the only attribute was: "objectclass: computer", then make sure we also add "user" objectclass */
468         if ( ! samldb_find_or_add_attribute(module, msg2, "objectclass", "user", "user")) {
469                 return NULL;
470         }
471
472         if ((attribute = samldb_find_attribute(msg2, "cn", NULL)) != NULL) {
473                 if (strcasecmp(&rdn[3], attribute->values[0].data) != 0) {
474                         ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_user_or_computer_object: Bad Attribute Syntax for CN\n");
475                         return NULL;
476                 }
477         } else { /* FIXME: remove this if ldb supports natively aliasing between the rdn and the "cn" attribute */
478                 if ( ! samldb_msg_add_string(module, msg2, "cn", &rdn[3])) {
479                         return NULL;
480                 }
481         }
482
483         if ((attribute = samldb_find_attribute(msg2, "name", NULL)) != NULL) {
484                 if (strcasecmp(&rdn[3], attribute->values[0].data) != 0) {
485                         ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_user_or_computer_object: Bad Attribute Syntax for name\n");
486                         return NULL;
487                 }
488         } else { /* FIXME: remove this if ldb supports natively aliasing between the rdn and the "name" attribute */
489                 if ( ! samldb_msg_add_string(module, msg2, "name", &rdn[3])) {
490                         return NULL;
491                 }
492         }
493
494         if ((attribute = samldb_find_attribute(msg2, "objectSid", NULL)) == NULL ) {
495
496                 if ((sidstr = samldb_get_new_sid(module, msg2, msg2->dn)) == NULL) {
497                         ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_user_or_computer_object: internal error! Can't generate new sid\n");
498                         return NULL;
499                 }
500
501                 if ( ! samldb_msg_add_string(module, msg2, "objectSid", sidstr)) {
502                         return NULL;
503                 }
504         }
505
506         if ( ! samldb_find_or_add_attribute(module, msg2, "sAMAccountName", NULL, samldb_generate_samAccountName(msg2))) {
507                 return NULL;
508         }
509
510         /* TODO: objectGUID, objectCategory, userAccountControl, badPwdCount, codePage, countryCode, badPasswordTime, lastLogoff, lastLogon, pwdLastSet, primaryGroupID, accountExpires, logonCount */
511
512         talloc_steal(msg, msg2);
513
514         return msg2;
515 }
516
517 /* add_record */
518 static int samldb_add_record(struct ldb_module *module, const struct ldb_message *msg)
519 {
520         struct ldb_message *msg2 = NULL;
521         int ret;
522
523         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "samldb_add_record\n");
524
525         if (msg->dn[0] == '@') { /* do not manipulate our control entries */
526                 return ldb_next_add_record(module, msg);
527         }
528
529         /* is user or computer?  add all relevant missing objects */
530         msg2 = samldb_fill_user_or_computer_object(module, msg);
531
532         /* is group? add all relevant missing objects */
533         if ( ! msg2 ) {
534                 msg2 = samldb_fill_group_object(module, msg);
535         }
536
537         if (msg2) {
538                 ret = ldb_next_add_record(module, msg2);
539         } else {
540                 ret = ldb_next_add_record(module, msg);
541         }
542
543         return ret;
544 }
545
546 /* modify_record: change modifyTimestamp as well */
547 static int samldb_modify_record(struct ldb_module *module, const struct ldb_message *msg)
548 {
549         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "samldb_modify_record\n");
550         return ldb_next_modify_record(module, msg);
551 }
552
553 static int samldb_delete_record(struct ldb_module *module, const char *dn)
554 {
555         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "samldb_delete_record\n");
556         return ldb_next_delete_record(module, dn);
557 }
558
559 static int samldb_rename_record(struct ldb_module *module, const char *olddn, const char *newdn)
560 {
561         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "samldb_rename_record\n");
562         return ldb_next_rename_record(module, olddn, newdn);
563 }
564
565 static int samldb_lock(struct ldb_module *module, const char *lockname)
566 {
567         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "samldb_lock\n");
568         return ldb_next_named_lock(module, lockname);
569 }
570
571 static int samldb_unlock(struct ldb_module *module, const char *lockname)
572 {
573         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "samldb_unlock\n");
574         return ldb_next_named_unlock(module, lockname);
575 }
576
577 /* return extended error information */
578 static const char *samldb_errstring(struct ldb_module *module)
579 {
580         struct private_data *data = (struct private_data *)module->private_data;
581
582         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "samldb_errstring\n");
583         if (data->error_string) {
584                 const char *error;
585
586                 error = data->error_string;
587                 data->error_string = NULL;
588                 return error;
589         }
590
591         return ldb_next_errstring(module);
592 }
593
594 static int samldb_destructor(void *module_ctx)
595 {
596         /* struct ldb_module *ctx = module_ctx; */
597         /* put your clean-up functions here */
598         return 0;
599 }
600
601 static const struct ldb_module_ops samldb_ops = {
602         "samldb",
603         samldb_search,
604         samldb_add_record,
605         samldb_modify_record,
606         samldb_delete_record,
607         samldb_rename_record,
608         samldb_lock,
609         samldb_unlock,
610         samldb_errstring
611 };
612
613
614 /* the init function */
615 #ifdef HAVE_DLOPEN_DISABLED
616  struct ldb_module *init_module(struct ldb_context *ldb, const char *options[])
617 #else
618 struct ldb_module *samldb_module_init(struct ldb_context *ldb, const char *options[])
619 #endif
620 {
621         struct ldb_module *ctx;
622         struct private_data *data;
623
624         ctx = talloc(ldb, struct ldb_module);
625         if (!ctx)
626                 return NULL;
627
628         data = talloc(ctx, struct private_data);
629         if (!data) {
630                 talloc_free(ctx);
631                 return NULL;
632         }
633
634         data->error_string = NULL;
635         ctx->private_data = data;
636         ctx->ldb = ldb;
637         ctx->prev = ctx->next = NULL;
638         ctx->ops = &samldb_ops;
639
640         talloc_set_destructor(ctx, samldb_destructor);
641
642         return ctx;
643 }