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