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