/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- samldb_ctx_init
- samldb_add_step
- samldb_first_step
- samldb_next_step
- samldb_search_template_callback
- samldb_search_template
- samldb_apply_template
- samldb_get_parent_domain_callback
- samldb_get_parent_domain
- samldb_generate_samAccountName
- samldb_check_samAccountName_callback
- samldb_check_samAccountName
- samldb_check_samAccountType
- samldb_get_sid_domain_callback
- samldb_get_sid_domain
- samldb_msg_add_sid
- samldb_new_sid
- samldb_check_sid_callback
- samldb_check_sid
- samldb_notice_sid_callback
- samldb_notice_sid
- samldb_add_entry_callback
- samldb_add_entry
- samldb_fill_object
- samldb_foreign_notice_sid_callback
- samldb_foreign_notice_sid
- samldb_fill_foreignSecurityPrincipal_object
- samldb_check_rdn
- samldb_add
- samldb_modify
- samldb_init
1 /*
2 SAM ldb module
3
4 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
5 Copyright (C) Simo Sorce 2004-2008
6
7 * NOTICE: this module is NOT released under the GNU LGPL license as
8 * other ldb code. This module is release under the GNU GPL v3 or
9 * later license.
10
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
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 "libcli/ldap/ldap_ndr.h"
37 #include "ldb_module.h"
38 #include "dsdb/samdb/samdb.h"
39 #include "libcli/security/security.h"
40 #include "librpc/gen_ndr/ndr_security.h"
41 #include "../lib/util/util_ldb.h"
42 #include "ldb_wrap.h"
43
44 struct samldb_ctx;
45
46 typedef int (*samldb_step_fn_t)(struct samldb_ctx *);
47
48 struct samldb_step {
49 struct samldb_step *next;
50 samldb_step_fn_t fn;
51 };
52
53 struct samldb_ctx {
54 struct ldb_module *module;
55 struct ldb_request *req;
56
57 /* the resulting message */
58 struct ldb_message *msg;
59
60 /* used to apply templates */
61 const char *type;
62
63 /* used to find parent domain */
64 struct ldb_dn *check_dn;
65 struct ldb_dn *domain_dn;
66 struct dom_sid *domain_sid;
67 uint32_t next_rid;
68
69 /* generic storage, remember to zero it before use */
70 struct ldb_reply *ares;
71
72 /* holds the entry SID */
73 struct dom_sid *sid;
74
75 /* all the async steps necessary to complete the operation */
76 struct samldb_step *steps;
77 struct samldb_step *curstep;
78 };
79
80 static struct samldb_ctx *samldb_ctx_init(struct ldb_module *module,
/* [<][>][^][v][top][bottom][index][help] */
81 struct ldb_request *req)
82 {
83 struct ldb_context *ldb;
84 struct samldb_ctx *ac;
85
86 ldb = ldb_module_get_ctx(module);
87
88 ac = talloc_zero(req, struct samldb_ctx);
89 if (ac == NULL) {
90 ldb_oom(ldb);
91 return NULL;
92 }
93
94 ac->module = module;
95 ac->req = req;
96
97 return ac;
98 }
99
100 static int samldb_add_step(struct samldb_ctx *ac, samldb_step_fn_t fn)
/* [<][>][^][v][top][bottom][index][help] */
101 {
102 struct samldb_step *step;
103
104 step = talloc_zero(ac, struct samldb_step);
105 if (step == NULL) {
106 return LDB_ERR_OPERATIONS_ERROR;
107 }
108
109 if (ac->steps == NULL) {
110 ac->steps = step;
111 ac->curstep = step;
112 } else {
113 ac->curstep->next = step;
114 ac->curstep = step;
115 }
116
117 step->fn = fn;
118
119 return LDB_SUCCESS;
120 }
121
122 static int samldb_first_step(struct samldb_ctx *ac)
/* [<][>][^][v][top][bottom][index][help] */
123 {
124 if (ac->steps == NULL) {
125 return LDB_ERR_OPERATIONS_ERROR;
126 }
127
128 ac->curstep = ac->steps;
129 return ac->curstep->fn(ac);
130 }
131
132 static int samldb_next_step(struct samldb_ctx *ac)
/* [<][>][^][v][top][bottom][index][help] */
133 {
134 if (ac->curstep->next) {
135 ac->curstep = ac->curstep->next;
136 return ac->curstep->fn(ac);
137 }
138
139 /* it is an error if the last step does not properly
140 * return to the upper module by itself */
141 return LDB_ERR_OPERATIONS_ERROR;
142 }
143
144 static int samldb_search_template_callback(struct ldb_request *req,
/* [<][>][^][v][top][bottom][index][help] */
145 struct ldb_reply *ares)
146 {
147 struct ldb_context *ldb;
148 struct samldb_ctx *ac;
149 int ret;
150
151 ac = talloc_get_type(req->context, struct samldb_ctx);
152 ldb = ldb_module_get_ctx(ac->module);
153
154 if (!ares) {
155 ret = LDB_ERR_OPERATIONS_ERROR;
156 goto done;
157 }
158 if (ares->error != LDB_SUCCESS) {
159 return ldb_module_done(ac->req, ares->controls,
160 ares->response, ares->error);
161 }
162
163 switch (ares->type) {
164 case LDB_REPLY_ENTRY:
165 /* save entry */
166 if (ac->ares != NULL) {
167 /* one too many! */
168 ldb_set_errstring(ldb,
169 "Invalid number of results while searching "
170 "for template objects");
171 ret = LDB_ERR_OPERATIONS_ERROR;
172 goto done;
173 }
174
175 ac->ares = talloc_steal(ac, ares);
176 ret = LDB_SUCCESS;
177 break;
178
179 case LDB_REPLY_REFERRAL:
180 /* ignore */
181 talloc_free(ares);
182 ret = LDB_SUCCESS;
183 break;
184
185 case LDB_REPLY_DONE:
186
187 talloc_free(ares);
188 ret = samldb_next_step(ac);
189 break;
190 }
191
192 done:
193 if (ret != LDB_SUCCESS) {
194 return ldb_module_done(ac->req, NULL, NULL, ret);
195 }
196
197 return LDB_SUCCESS;
198 }
199
200 static int samldb_search_template(struct samldb_ctx *ac)
/* [<][>][^][v][top][bottom][index][help] */
201 {
202 struct ldb_context *ldb;
203 struct tevent_context *ev;
204 struct loadparm_context *lparm_ctx;
205 struct ldb_context *templates_ldb;
206 char *templates_ldb_path;
207 struct ldb_request *req;
208 struct ldb_dn *basedn;
209 void *opaque;
210 int ret;
211
212 ldb = ldb_module_get_ctx(ac->module);
213
214 opaque = ldb_get_opaque(ldb, "loadparm");
215 lparm_ctx = talloc_get_type(opaque, struct loadparm_context);
216 if (lparm_ctx == NULL) {
217 ldb_set_errstring(ldb,
218 "Unable to find loadparm context\n");
219 return LDB_ERR_OPERATIONS_ERROR;
220 }
221
222 opaque = ldb_get_opaque(ldb, "templates_ldb");
223 templates_ldb = talloc_get_type(opaque, struct ldb_context);
224
225 /* make sure we have the templates ldb */
226 if (!templates_ldb) {
227 templates_ldb_path = samdb_relative_path(ldb, ac,
228 "templates.ldb");
229 if (!templates_ldb_path) {
230 ldb_set_errstring(ldb,
231 "samldb_init_template: ERROR: Failed "
232 "to contruct path for template db");
233 return LDB_ERR_OPERATIONS_ERROR;
234 }
235
236 ev = ldb_get_event_context(ldb);
237
238 templates_ldb = ldb_wrap_connect(ldb, ev,
239 lparm_ctx, templates_ldb_path,
240 NULL, NULL, 0, NULL);
241 talloc_free(templates_ldb_path);
242
243 if (!templates_ldb) {
244 return LDB_ERR_OPERATIONS_ERROR;
245 }
246
247 if (!talloc_reference(templates_ldb, ev)) {
248 return LDB_ERR_OPERATIONS_ERROR;
249 }
250
251 ret = ldb_set_opaque(ldb,
252 "templates_ldb", templates_ldb);
253 if (ret != LDB_SUCCESS) {
254 return ret;
255 }
256 }
257
258 /* search template */
259 basedn = ldb_dn_new_fmt(ac, templates_ldb,
260 "cn=Template%s,cn=Templates", ac->type);
261 if (basedn == NULL) {
262 ldb_set_errstring(ldb,
263 "samldb_init_template: ERROR: Failed "
264 "to contruct DN for template");
265 return LDB_ERR_OPERATIONS_ERROR;
266 }
267
268 /* pull the template record */
269 ret = ldb_build_search_req(&req, templates_ldb, ac,
270 basedn, LDB_SCOPE_BASE,
271 "(distinguishedName=*)", NULL,
272 NULL,
273 ac, samldb_search_template_callback,
274 ac->req);
275 if (ret != LDB_SUCCESS) {
276 return ret;
277 }
278
279 talloc_steal(req, basedn);
280 ac->ares = NULL;
281
282 return ldb_request(templates_ldb, req);
283 }
284
285 static int samldb_apply_template(struct samldb_ctx *ac)
/* [<][>][^][v][top][bottom][index][help] */
286 {
287 struct ldb_context *ldb;
288 struct ldb_message_element *el;
289 struct ldb_message *msg;
290 int i, j;
291 int ret;
292
293 ldb = ldb_module_get_ctx(ac->module);
294 msg = ac->ares->message;
295
296 for (i = 0; i < msg->num_elements; i++) {
297 el = &msg->elements[i];
298 /* some elements should not be copied */
299 if (ldb_attr_cmp(el->name, "cn") == 0 ||
300 ldb_attr_cmp(el->name, "name") == 0 ||
301 ldb_attr_cmp(el->name, "objectClass") == 0 ||
302 ldb_attr_cmp(el->name, "sAMAccountName") == 0 ||
303 ldb_attr_cmp(el->name, "sAMAccountName") == 0 ||
304 ldb_attr_cmp(el->name, "distinguishedName") == 0 ||
305 ldb_attr_cmp(el->name, "objectGUID") == 0) {
306 continue;
307 }
308 for (j = 0; j < el->num_values; j++) {
309 ret = samdb_find_or_add_attribute(
310 ldb, ac->msg, el->name,
311 (char *)el->values[j].data);
312 if (ret != LDB_SUCCESS) {
313 ldb_set_errstring(ldb,
314 "Failed adding template attribute\n");
315 return LDB_ERR_OPERATIONS_ERROR;
316 }
317 }
318 }
319
320 return samldb_next_step(ac);
321 }
322
323 static int samldb_get_parent_domain(struct samldb_ctx *ac);
324
325 static int samldb_get_parent_domain_callback(struct ldb_request *req,
/* [<][>][^][v][top][bottom][index][help] */
326 struct ldb_reply *ares)
327 {
328 struct ldb_context *ldb;
329 struct samldb_ctx *ac;
330 const char *nextRid;
331 int ret;
332
333 ac = talloc_get_type(req->context, struct samldb_ctx);
334 ldb = ldb_module_get_ctx(ac->module);
335
336 if (!ares) {
337 ret = LDB_ERR_OPERATIONS_ERROR;
338 goto done;
339 }
340 if (ares->error != LDB_SUCCESS) {
341 return ldb_module_done(ac->req, ares->controls,
342 ares->response, ares->error);
343 }
344
345 switch (ares->type) {
346 case LDB_REPLY_ENTRY:
347 /* save entry */
348 if (ac->domain_dn != NULL) {
349 /* one too many! */
350 ldb_set_errstring(ldb,
351 "Invalid number of results while searching "
352 "for domain object");
353 ret = LDB_ERR_OPERATIONS_ERROR;
354 break;
355 }
356
357 nextRid = ldb_msg_find_attr_as_string(ares->message,
358 "nextRid", NULL);
359 if (nextRid == NULL) {
360 ldb_asprintf_errstring(ldb,
361 "while looking for domain above %s attribute nextRid not found in %s\n",
362 ldb_dn_get_linearized(ac->req->op.add.message->dn),
363 ldb_dn_get_linearized(ares->message->dn));
364 ret = LDB_ERR_OPERATIONS_ERROR;
365 break;
366 }
367
368 ac->next_rid = strtol(nextRid, NULL, 0);
369
370 ac->domain_sid = samdb_result_dom_sid(ac, ares->message,
371 "objectSid");
372 if (ac->domain_sid == NULL) {
373 ldb_set_errstring(ldb,
374 "error retrieving parent domain domain sid!\n");
375 ret = LDB_ERR_CONSTRAINT_VIOLATION;
376 break;
377 }
378 ac->domain_dn = talloc_steal(ac, ares->message->dn);
379
380 talloc_free(ares);
381 ret = LDB_SUCCESS;
382 ldb_reset_err_string(ldb);
383 break;
384
385 case LDB_REPLY_REFERRAL:
386 /* ignore */
387 talloc_free(ares);
388 ret = LDB_SUCCESS;
389 break;
390
391 case LDB_REPLY_DONE:
392
393 talloc_free(ares);
394 if (ac->domain_dn == NULL) {
395 /* search again */
396 ret = samldb_get_parent_domain(ac);
397 } else {
398 /* found, go on */
399 ret = samldb_next_step(ac);
400 }
401 break;
402 }
403
404 done:
405 if (ret != LDB_SUCCESS) {
406 return ldb_module_done(ac->req, NULL, NULL, ret);
407 }
408
409 return LDB_SUCCESS;
410 }
411
412 /* Find a domain object in the parents of a particular DN. */
413 static int samldb_get_parent_domain(struct samldb_ctx *ac)
/* [<][>][^][v][top][bottom][index][help] */
414 {
415 struct ldb_context *ldb;
416 static const char * const attrs[3] = { "objectSid", "nextRid", NULL };
417 struct ldb_request *req;
418 struct ldb_dn *dn;
419 int ret;
420
421 ldb = ldb_module_get_ctx(ac->module);
422
423 if (ac->check_dn == NULL) {
424 return LDB_ERR_OPERATIONS_ERROR;
425 }
426
427 dn = ldb_dn_get_parent(ac, ac->check_dn);
428 if (dn == NULL) {
429 ldb_set_errstring(ldb,
430 "Unable to find parent domain object");
431 return LDB_ERR_CONSTRAINT_VIOLATION;
432 }
433
434 ac->check_dn = dn;
435
436 ret = ldb_build_search_req(&req, ldb, ac,
437 dn, LDB_SCOPE_BASE,
438 "(|(objectClass=domain)"
439 "(objectClass=builtinDomain)"
440 "(objectClass=samba4LocalDomain))",
441 attrs,
442 NULL,
443 ac, samldb_get_parent_domain_callback,
444 ac->req);
445
446 if (ret != LDB_SUCCESS) {
447 return ret;
448 }
449
450 return ldb_next_request(ac->module, req);
451 }
452
453 static int samldb_generate_samAccountName(struct ldb_message *msg)
/* [<][>][^][v][top][bottom][index][help] */
454 {
455 char *name;
456
457 /* Format: $000000-000000000000 */
458
459 name = talloc_asprintf(msg, "$%.6X-%.6X%.6X",
460 (unsigned int)generate_random(),
461 (unsigned int)generate_random(),
462 (unsigned int)generate_random());
463 if (name == NULL) {
464 return LDB_ERR_OPERATIONS_ERROR;
465 }
466 return ldb_msg_add_steal_string(msg, "samAccountName", name);
467 }
468
469 static int samldb_check_samAccountName_callback(struct ldb_request *req,
/* [<][>][^][v][top][bottom][index][help] */
470 struct ldb_reply *ares)
471 {
472 struct samldb_ctx *ac;
473 int ret;
474
475 ac = talloc_get_type(req->context, struct samldb_ctx);
476
477 if (!ares) {
478 ret = LDB_ERR_OPERATIONS_ERROR;
479 goto done;
480 }
481 if (ares->error != LDB_SUCCESS) {
482 return ldb_module_done(ac->req, ares->controls,
483 ares->response, ares->error);
484 }
485
486 switch (ares->type) {
487 case LDB_REPLY_ENTRY:
488
489 /* if we get an entry it means this samAccountName
490 * already exists */
491 return ldb_module_done(ac->req, NULL, NULL,
492 LDB_ERR_ENTRY_ALREADY_EXISTS);
493
494 case LDB_REPLY_REFERRAL:
495 /* ignore */
496 talloc_free(ares);
497 ret = LDB_SUCCESS;
498 break;
499
500 case LDB_REPLY_DONE:
501
502 /* not found, go on */
503 talloc_free(ares);
504 ret = samldb_next_step(ac);
505 break;
506 }
507
508 done:
509 if (ret != LDB_SUCCESS) {
510 return ldb_module_done(ac->req, NULL, NULL, ret);
511 }
512
513 return LDB_SUCCESS;
514 }
515
516 static int samldb_check_samAccountName(struct samldb_ctx *ac)
/* [<][>][^][v][top][bottom][index][help] */
517 {
518 struct ldb_context *ldb;
519 struct ldb_request *req;
520 const char *name;
521 char *filter;
522 int ret;
523
524 ldb = ldb_module_get_ctx(ac->module);
525
526 if (ldb_msg_find_element(ac->msg, "samAccountName") == NULL) {
527 ret = samldb_generate_samAccountName(ac->msg);
528 if (ret != LDB_SUCCESS) {
529 return ret;
530 }
531 }
532
533 name = ldb_msg_find_attr_as_string(ac->msg, "samAccountName", NULL);
534 if (name == NULL) {
535 return LDB_ERR_OPERATIONS_ERROR;
536 }
537 filter = talloc_asprintf(ac, "samAccountName=%s", name);
538 if (filter == NULL) {
539 return LDB_ERR_OPERATIONS_ERROR;
540 }
541
542 ret = ldb_build_search_req(&req, ldb, ac,
543 ac->domain_dn, LDB_SCOPE_SUBTREE,
544 filter, NULL,
545 NULL,
546 ac, samldb_check_samAccountName_callback,
547 ac->req);
548 talloc_free(filter);
549 if (ret != LDB_SUCCESS) {
550 return ret;
551 }
552 ac->ares = NULL;
553 return ldb_next_request(ac->module, req);
554 }
555
556 static int samldb_check_samAccountType(struct samldb_ctx *ac)
/* [<][>][^][v][top][bottom][index][help] */
557 {
558 struct ldb_context *ldb;
559 unsigned int account_type;
560 unsigned int group_type;
561 unsigned int uac;
562 int ret;
563
564 ldb = ldb_module_get_ctx(ac->module);
565
566 /* make sure sAMAccountType is not specified */
567 if (ldb_msg_find_element(ac->msg, "sAMAccountType") != NULL) {
568 ldb_asprintf_errstring(ldb,
569 "sAMAccountType must not be specified");
570 return LDB_ERR_UNWILLING_TO_PERFORM;
571 }
572
573 if (strcmp("user", ac->type) == 0) {
574 uac = samdb_result_uint(ac->msg, "userAccountControl", 0);
575 if (uac == 0) {
576 ldb_asprintf_errstring(ldb,
577 "userAccountControl invalid");
578 return LDB_ERR_UNWILLING_TO_PERFORM;
579 } else {
580 account_type = samdb_uf2atype(uac);
581 ret = samdb_msg_add_uint(ldb,
582 ac->msg, ac->msg,
583 "sAMAccountType",
584 account_type);
585 if (ret != LDB_SUCCESS) {
586 return ret;
587 }
588 }
589 } else
590 if (strcmp("group", ac->type) == 0) {
591
592 group_type = samdb_result_uint(ac->msg, "groupType", 0);
593 if (group_type == 0) {
594 ldb_asprintf_errstring(ldb,
595 "groupType invalid");
596 return LDB_ERR_UNWILLING_TO_PERFORM;
597 } else {
598 account_type = samdb_gtype2atype(group_type);
599 ret = samdb_msg_add_uint(ldb,
600 ac->msg, ac->msg,
601 "sAMAccountType",
602 account_type);
603 if (ret != LDB_SUCCESS) {
604 return ret;
605 }
606 }
607 }
608
609 return samldb_next_step(ac);
610 }
611
612 static int samldb_get_sid_domain_callback(struct ldb_request *req,
/* [<][>][^][v][top][bottom][index][help] */
613 struct ldb_reply *ares)
614 {
615 struct ldb_context *ldb;
616 struct samldb_ctx *ac;
617 const char *nextRid;
618 int ret;
619
620 ac = talloc_get_type(req->context, struct samldb_ctx);
621 ldb = ldb_module_get_ctx(ac->module);
622
623 if (!ares) {
624 ret = LDB_ERR_OPERATIONS_ERROR;
625 goto done;
626 }
627 if (ares->error != LDB_SUCCESS) {
628 return ldb_module_done(ac->req, ares->controls,
629 ares->response, ares->error);
630 }
631
632 switch (ares->type) {
633 case LDB_REPLY_ENTRY:
634 /* save entry */
635 if (ac->next_rid != 0) {
636 /* one too many! */
637 ldb_set_errstring(ldb,
638 "Invalid number of results while searching "
639 "for domain object");
640 ret = LDB_ERR_OPERATIONS_ERROR;
641 break;
642 }
643
644 nextRid = ldb_msg_find_attr_as_string(ares->message,
645 "nextRid", NULL);
646 if (nextRid == NULL) {
647 ldb_asprintf_errstring(ldb,
648 "attribute nextRid not found in %s\n",
649 ldb_dn_get_linearized(ares->message->dn));
650 ret = LDB_ERR_OPERATIONS_ERROR;
651 break;
652 }
653
654 ac->next_rid = strtol(nextRid, NULL, 0);
655
656 ac->domain_dn = talloc_steal(ac, ares->message->dn);
657
658 talloc_free(ares);
659 ret = LDB_SUCCESS;
660 break;
661
662 case LDB_REPLY_REFERRAL:
663 /* ignore */
664 talloc_free(ares);
665 ret = LDB_SUCCESS;
666 break;
667
668 case LDB_REPLY_DONE:
669
670 if (ac->next_rid == 0) {
671 ldb_asprintf_errstring(ldb,
672 "Unable to get nextRid from domain entry\n");
673 ret = LDB_ERR_OPERATIONS_ERROR;
674 break;
675 }
676
677 /* found, go on */
678 ret = samldb_next_step(ac);
679 break;
680 }
681
682 done:
683 if (ret != LDB_SUCCESS) {
684 return ldb_module_done(ac->req, NULL, NULL, ret);
685 }
686
687 return LDB_SUCCESS;
688 }
689
690 /* Find a domain object in the parents of a particular DN. */
691 static int samldb_get_sid_domain(struct samldb_ctx *ac)
/* [<][>][^][v][top][bottom][index][help] */
692 {
693 struct ldb_context *ldb;
694 static const char * const attrs[2] = { "nextRid", NULL };
695 struct ldb_request *req;
696 char *filter;
697 int ret;
698
699 ldb = ldb_module_get_ctx(ac->module);
700
701 if (ac->sid == NULL) {
702 return LDB_ERR_OPERATIONS_ERROR;
703 }
704
705 ac->domain_sid = dom_sid_dup(ac, ac->sid);
706 if (!ac->domain_sid) {
707 return LDB_ERR_OPERATIONS_ERROR;
708 }
709 /* get the domain component part of the provided SID */
710 ac->domain_sid->num_auths--;
711
712 filter = talloc_asprintf(ac, "(&(objectSid=%s)"
713 "(|(objectClass=domain)"
714 "(objectClass=builtinDomain)"
715 "(objectClass=samba4LocalDomain)))",
716 ldap_encode_ndr_dom_sid(ac, ac->domain_sid));
717 if (filter == NULL) {
718 return LDB_ERR_OPERATIONS_ERROR;
719 }
720
721 ret = ldb_build_search_req(&req, ldb, ac,
722 ldb_get_default_basedn(ldb),
723 LDB_SCOPE_SUBTREE,
724 filter, attrs,
725 NULL,
726 ac, samldb_get_sid_domain_callback,
727 ac->req);
728
729 if (ret != LDB_SUCCESS) {
730 return ret;
731 }
732
733 ac->next_rid = 0;
734 return ldb_next_request(ac->module, req);
735 }
736
737 static bool samldb_msg_add_sid(struct ldb_message *msg,
/* [<][>][^][v][top][bottom][index][help] */
738 const char *name,
739 const struct dom_sid *sid)
740 {
741 struct ldb_val v;
742 enum ndr_err_code ndr_err;
743
744 ndr_err = ndr_push_struct_blob(&v, msg, NULL, sid,
745 (ndr_push_flags_fn_t)ndr_push_dom_sid);
746 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
747 return false;
748 }
749 return (ldb_msg_add_value(msg, name, &v, NULL) == 0);
750 }
751
752 static int samldb_new_sid(struct samldb_ctx *ac)
/* [<][>][^][v][top][bottom][index][help] */
753 {
754
755 if (ac->domain_sid == NULL || ac->next_rid == 0) {
756 return LDB_ERR_OPERATIONS_ERROR;
757 }
758
759 ac->sid = dom_sid_add_rid(ac, ac->domain_sid, ac->next_rid + 1);
760 if (ac->sid == NULL) {
761 return LDB_ERR_OPERATIONS_ERROR;
762 }
763
764 if ( ! samldb_msg_add_sid(ac->msg, "objectSid", ac->sid)) {
765 return LDB_ERR_OPERATIONS_ERROR;
766 }
767
768 return samldb_next_step(ac);
769 }
770
771 static int samldb_check_sid_callback(struct ldb_request *req,
/* [<][>][^][v][top][bottom][index][help] */
772 struct ldb_reply *ares)
773 {
774 struct samldb_ctx *ac;
775 int ret;
776
777 ac = talloc_get_type(req->context, struct samldb_ctx);
778
779 if (!ares) {
780 ret = LDB_ERR_OPERATIONS_ERROR;
781 goto done;
782 }
783 if (ares->error != LDB_SUCCESS) {
784 return ldb_module_done(ac->req, ares->controls,
785 ares->response, ares->error);
786 }
787
788 switch (ares->type) {
789 case LDB_REPLY_ENTRY:
790
791 /* if we get an entry it means an object with the
792 * requested sid exists */
793 return ldb_module_done(ac->req, NULL, NULL,
794 LDB_ERR_CONSTRAINT_VIOLATION);
795
796 case LDB_REPLY_REFERRAL:
797 /* ignore */
798 talloc_free(ares);
799 break;
800
801 case LDB_REPLY_DONE:
802
803 /* not found, go on */
804 talloc_free(ares);
805 ret = samldb_next_step(ac);
806 break;
807 }
808
809 done:
810 if (ret != LDB_SUCCESS) {
811 return ldb_module_done(ac->req, NULL, NULL, ret);
812 }
813
814 return LDB_SUCCESS;
815 }
816
817 static int samldb_check_sid(struct samldb_ctx *ac)
/* [<][>][^][v][top][bottom][index][help] */
818 {
819 struct ldb_context *ldb;
820 const char *const attrs[2] = { "objectSid", NULL };
821 struct ldb_request *req;
822 char *filter;
823 int ret;
824
825 if (ac->sid == NULL) {
826 return LDB_ERR_OPERATIONS_ERROR;
827 }
828
829 ldb = ldb_module_get_ctx(ac->module);
830
831 filter = talloc_asprintf(ac, "(objectSid=%s)",
832 ldap_encode_ndr_dom_sid(ac, ac->sid));
833 if (filter == NULL) {
834 return LDB_ERR_OPERATIONS_ERROR;
835 }
836
837 ret = ldb_build_search_req(&req, ldb, ac,
838 ldb_get_default_basedn(ldb),
839 LDB_SCOPE_SUBTREE,
840 filter, attrs,
841 NULL,
842 ac, samldb_check_sid_callback,
843 ac->req);
844
845 if (ret != LDB_SUCCESS) {
846 return ret;
847 }
848
849 return ldb_next_request(ac->module, req);
850 }
851
852 static int samldb_notice_sid_callback(struct ldb_request *req,
/* [<][>][^][v][top][bottom][index][help] */
853 struct ldb_reply *ares)
854 {
855 struct ldb_context *ldb;
856 struct samldb_ctx *ac;
857 int ret;
858
859 ac = talloc_get_type(req->context, struct samldb_ctx);
860 ldb = ldb_module_get_ctx(ac->module);
861
862 if (!ares) {
863 ret = LDB_ERR_OPERATIONS_ERROR;
864 goto done;
865 }
866 if (ares->error != LDB_SUCCESS) {
867 return ldb_module_done(ac->req, ares->controls,
868 ares->response, ares->error);
869 }
870 if (ares->type != LDB_REPLY_DONE) {
871 ldb_set_errstring(ldb,
872 "Invalid reply type!\n");
873 ret = LDB_ERR_OPERATIONS_ERROR;
874 goto done;
875 }
876
877 ret = samldb_next_step(ac);
878
879 done:
880 if (ret != LDB_SUCCESS) {
881 return ldb_module_done(ac->req, NULL, NULL, ret);
882 }
883
884 return LDB_SUCCESS;
885 }
886
887 /* If we are adding new users/groups, we need to update the nextRid
888 * attribute to be 'above' the new/incoming RID. Attempt to do it
889 *atomically. */
890 static int samldb_notice_sid(struct samldb_ctx *ac)
/* [<][>][^][v][top][bottom][index][help] */
891 {
892 struct ldb_context *ldb;
893 uint32_t old_id, new_id;
894 struct ldb_request *req;
895 struct ldb_message *msg;
896 struct ldb_message_element *els;
897 struct ldb_val *vals;
898 int ret;
899
900 ldb = ldb_module_get_ctx(ac->module);
901 old_id = ac->next_rid;
902 new_id = ac->sid->sub_auths[ac->sid->num_auths - 1];
903
904 if (old_id >= new_id) {
905 /* no need to update the domain nextRid attribute */
906 return samldb_next_step(ac);
907 }
908
909 /* we do a delete and add as a single operation. That prevents
910 a race, in case we are not actually on a transaction db */
911 msg = talloc_zero(ac, struct ldb_message);
912 if (msg == NULL) {
913 ldb_oom(ldb);
914 return LDB_ERR_OPERATIONS_ERROR;
915 }
916 els = talloc_array(msg, struct ldb_message_element, 2);
917 if (els == NULL) {
918 ldb_oom(ldb);
919 return LDB_ERR_OPERATIONS_ERROR;
920 }
921 vals = talloc_array(msg, struct ldb_val, 2);
922 if (vals == NULL) {
923 ldb_oom(ldb);
924 return LDB_ERR_OPERATIONS_ERROR;
925 }
926 msg->dn = ac->domain_dn;
927 msg->num_elements = 2;
928 msg->elements = els;
929
930 els[0].num_values = 1;
931 els[0].values = &vals[0];
932 els[0].flags = LDB_FLAG_MOD_DELETE;
933 els[0].name = talloc_strdup(msg, "nextRid");
934 if (!els[0].name) {
935 ldb_oom(ldb);
936 return LDB_ERR_OPERATIONS_ERROR;
937 }
938
939 els[1].num_values = 1;
940 els[1].values = &vals[1];
941 els[1].flags = LDB_FLAG_MOD_ADD;
942 els[1].name = els[0].name;
943
944 vals[0].data = (uint8_t *)talloc_asprintf(vals, "%u", old_id);
945 if (!vals[0].data) {
946 ldb_oom(ldb);
947 return LDB_ERR_OPERATIONS_ERROR;
948 }
949 vals[0].length = strlen((char *)vals[0].data);
950
951 vals[1].data = (uint8_t *)talloc_asprintf(vals, "%u", new_id);
952 if (!vals[1].data) {
953 ldb_oom(ldb);
954 return LDB_ERR_OPERATIONS_ERROR;
955 }
956 vals[1].length = strlen((char *)vals[1].data);
957
958 ret = ldb_build_mod_req(&req, ldb, ac,
959 msg, NULL,
960 ac, samldb_notice_sid_callback,
961 ac->req);
962 if (ret != LDB_SUCCESS) {
963 return ret;
964 }
965
966 return ldb_next_request(ac->module, req);
967 }
968
969 static int samldb_add_entry_callback(struct ldb_request *req,
/* [<][>][^][v][top][bottom][index][help] */
970 struct ldb_reply *ares)
971 {
972 struct ldb_context *ldb;
973 struct samldb_ctx *ac;
974
975 ac = talloc_get_type(req->context, struct samldb_ctx);
976 ldb = ldb_module_get_ctx(ac->module);
977
978 if (!ares) {
979 return ldb_module_done(ac->req, NULL, NULL,
980 LDB_ERR_OPERATIONS_ERROR);
981 }
982 if (ares->error != LDB_SUCCESS) {
983 return ldb_module_done(ac->req, ares->controls,
984 ares->response, ares->error);
985 }
986 if (ares->type != LDB_REPLY_DONE) {
987 ldb_set_errstring(ldb,
988 "Invalid reply type!\n");
989 return ldb_module_done(ac->req, NULL, NULL,
990 LDB_ERR_OPERATIONS_ERROR);
991 }
992
993 /* we exit the samldb module here */
994 return ldb_module_done(ac->req, ares->controls,
995 ares->response, LDB_SUCCESS);
996 }
997
998 static int samldb_add_entry(struct samldb_ctx *ac)
/* [<][>][^][v][top][bottom][index][help] */
999 {
1000 struct ldb_context *ldb;
1001 struct ldb_request *req;
1002 int ret;
1003
1004 ldb = ldb_module_get_ctx(ac->module);
1005
1006 ret = ldb_build_add_req(&req, ldb, ac,
1007 ac->msg,
1008 ac->req->controls,
1009 ac, samldb_add_entry_callback,
1010 ac->req);
1011 if (ret != LDB_SUCCESS) {
1012 return ret;
1013 }
1014
1015 return ldb_next_request(ac->module, req);
1016 }
1017
1018 static int samldb_fill_object(struct samldb_ctx *ac, const char *type)
/* [<][>][^][v][top][bottom][index][help] */
1019 {
1020 int ret;
1021
1022 /* first look for the template */
1023 ac->type = type;
1024 ret = samldb_add_step(ac, samldb_search_template);
1025 if (ret != LDB_SUCCESS) return ret;
1026
1027 /* then apply it */
1028 ret = samldb_add_step(ac, samldb_apply_template);
1029 if (ret != LDB_SUCCESS) return ret;
1030
1031 /* search for a parent domain objet */
1032 ac->check_dn = ac->req->op.add.message->dn;
1033 ret = samldb_add_step(ac, samldb_get_parent_domain);
1034 if (ret != LDB_SUCCESS) return ret;
1035
1036 /* check if we have a valid samAccountName */
1037 ret = samldb_add_step(ac, samldb_check_samAccountName);
1038 if (ret != LDB_SUCCESS) return ret;
1039
1040 /* check account_type/group_type */
1041 ret = samldb_add_step(ac, samldb_check_samAccountType);
1042 if (ret != LDB_SUCCESS) return ret;
1043
1044 /* check if we have a valid SID */
1045 ac->sid = samdb_result_dom_sid(ac, ac->msg, "objectSid");
1046 if ( ! ac->sid) {
1047 ret = samldb_add_step(ac, samldb_new_sid);
1048 if (ret != LDB_SUCCESS) return ret;
1049 } else {
1050 ret = samldb_add_step(ac, samldb_get_sid_domain);
1051 if (ret != LDB_SUCCESS) return ret;
1052 }
1053
1054 ret = samldb_add_step(ac, samldb_check_sid);
1055 if (ret != LDB_SUCCESS) return ret;
1056
1057 ret = samldb_add_step(ac, samldb_notice_sid);
1058 if (ret != LDB_SUCCESS) return ret;
1059
1060 /* finally proceed with adding the entry */
1061 ret = samldb_add_step(ac, samldb_add_entry);
1062 if (ret != LDB_SUCCESS) return ret;
1063
1064 return samldb_first_step(ac);
1065
1066 /* TODO: userAccountControl, badPwdCount, codePage,
1067 * countryCode, badPasswordTime, lastLogoff, lastLogon,
1068 * pwdLastSet, primaryGroupID, accountExpires, logonCount */
1069
1070 }
1071
1072 static int samldb_foreign_notice_sid_callback(struct ldb_request *req,
/* [<][>][^][v][top][bottom][index][help] */
1073 struct ldb_reply *ares)
1074 {
1075 struct ldb_context *ldb;
1076 struct samldb_ctx *ac;
1077 const char *nextRid;
1078 const char *name;
1079 int ret;
1080
1081 ac = talloc_get_type(req->context, struct samldb_ctx);
1082 ldb = ldb_module_get_ctx(ac->module);
1083
1084 if (!ares) {
1085 ret = LDB_ERR_OPERATIONS_ERROR;
1086 goto done;
1087 }
1088 if (ares->error != LDB_SUCCESS) {
1089 return ldb_module_done(ac->req, ares->controls,
1090 ares->response, ares->error);
1091 }
1092
1093 switch (ares->type) {
1094 case LDB_REPLY_ENTRY:
1095 /* save entry */
1096 if (ac->next_rid != 0) {
1097 /* one too many! */
1098 ldb_set_errstring(ldb,
1099 "Invalid number of results while searching "
1100 "for domain object");
1101 ret = LDB_ERR_OPERATIONS_ERROR;
1102 break;
1103 }
1104
1105 nextRid = ldb_msg_find_attr_as_string(ares->message,
1106 "nextRid", NULL);
1107 if (nextRid == NULL) {
1108 ldb_asprintf_errstring(ldb,
1109 "while looking for forign sid %s attribute nextRid not found in %s\n",
1110 dom_sid_string(ares, ac->sid), ldb_dn_get_linearized(ares->message->dn));
1111 ret = LDB_ERR_OPERATIONS_ERROR;
1112 break;
1113 }
1114
1115 ac->next_rid = strtol(nextRid, NULL, 0);
1116
1117 ac->domain_dn = talloc_steal(ac, ares->message->dn);
1118
1119 name = samdb_result_string(ares->message, "name", NULL);
1120 ldb_debug(ldb, LDB_DEBUG_TRACE,
1121 "NOTE (strange but valid): Adding foreign SID "
1122 "record with SID %s, but this domain (%s) is "
1123 "not foreign in the database",
1124 dom_sid_string(ares, ac->sid), name);
1125
1126 talloc_free(ares);
1127 break;
1128
1129 case LDB_REPLY_REFERRAL:
1130 /* ignore */
1131 talloc_free(ares);
1132 break;
1133
1134 case LDB_REPLY_DONE:
1135
1136 /* if this is a fake foreign SID, notice the SID */
1137 if (ac->domain_dn) {
1138 ret = samldb_notice_sid(ac);
1139 break;
1140 }
1141
1142 /* found, go on */
1143 ret = samldb_next_step(ac);
1144 break;
1145 }
1146
1147 done:
1148 if (ret != LDB_SUCCESS) {
1149 return ldb_module_done(ac->req, NULL, NULL, ret);
1150 }
1151
1152 return LDB_SUCCESS;
1153 }
1154
1155 /* Find a domain object in the parents of a particular DN. */
1156 static int samldb_foreign_notice_sid(struct samldb_ctx *ac)
/* [<][>][^][v][top][bottom][index][help] */
1157 {
1158 struct ldb_context *ldb;
1159 static const char * const attrs[3] = { "nextRid", "name", NULL };
1160 struct ldb_request *req;
1161 NTSTATUS status;
1162 char *filter;
1163 int ret;
1164
1165 ldb = ldb_module_get_ctx(ac->module);
1166
1167 if (ac->sid == NULL) {
1168 return LDB_ERR_OPERATIONS_ERROR;
1169 }
1170
1171 status = dom_sid_split_rid(ac, ac->sid, &ac->domain_sid, NULL);
1172 if (!NT_STATUS_IS_OK(status)) {
1173 return LDB_ERR_OPERATIONS_ERROR;
1174 }
1175
1176 filter = talloc_asprintf(ac, "(&(objectSid=%s)(objectclass=domain))",
1177 ldap_encode_ndr_dom_sid(ac, ac->domain_sid));
1178 if (filter == NULL) {
1179 return LDB_ERR_OPERATIONS_ERROR;
1180 }
1181
1182 ret = ldb_build_search_req(&req, ldb, ac,
1183 ldb_get_default_basedn(ldb),
1184 LDB_SCOPE_SUBTREE,
1185 filter, attrs,
1186 NULL,
1187 ac, samldb_foreign_notice_sid_callback,
1188 ac->req);
1189
1190 if (ret != LDB_SUCCESS) {
1191 return ret;
1192 }
1193
1194 ac->next_rid = 0;
1195 return ldb_next_request(ac->module, req);
1196 }
1197
1198 static int samldb_fill_foreignSecurityPrincipal_object(struct samldb_ctx *ac)
/* [<][>][^][v][top][bottom][index][help] */
1199 {
1200 struct ldb_context *ldb;
1201 int ret;
1202
1203 ldb = ldb_module_get_ctx(ac->module);
1204
1205 ac->sid = samdb_result_dom_sid(ac->msg, ac->msg, "objectSid");
1206 if (ac->sid == NULL) {
1207 ac->sid = dom_sid_parse_talloc(ac->msg,
1208 (const char *)ldb_dn_get_rdn_val(ac->msg->dn)->data);
1209 if (!ac->sid) {
1210 ldb_set_errstring(ldb,
1211 "No valid found SID in "
1212 "ForeignSecurityPrincipal CN!");
1213 talloc_free(ac);
1214 return LDB_ERR_CONSTRAINT_VIOLATION;
1215 }
1216 if ( ! samldb_msg_add_sid(ac->msg, "objectSid", ac->sid)) {
1217 talloc_free(ac);
1218 return LDB_ERR_OPERATIONS_ERROR;
1219 }
1220 }
1221
1222 /* first look for the template */
1223 ac->type = "foreignSecurityPrincipal";
1224 ret = samldb_add_step(ac, samldb_search_template);
1225 if (ret != LDB_SUCCESS) return ret;
1226
1227 /* then apply it */
1228 ret = samldb_add_step(ac, samldb_apply_template);
1229 if (ret != LDB_SUCCESS) return ret;
1230
1231 /* check we do not already have this SID */
1232 ret = samldb_add_step(ac, samldb_check_sid);
1233 if (ret != LDB_SUCCESS) return ret;
1234
1235 /* check if we need to notice this SID */
1236 ret = samldb_add_step(ac, samldb_foreign_notice_sid);
1237 if (ret != LDB_SUCCESS) return ret;
1238
1239 /* finally proceed with adding the entry */
1240 ret = samldb_add_step(ac, samldb_add_entry);
1241 if (ret != LDB_SUCCESS) return ret;
1242
1243 return samldb_first_step(ac);
1244 }
1245
1246 static int samldb_check_rdn(struct ldb_module *module, struct ldb_dn *dn)
/* [<][>][^][v][top][bottom][index][help] */
1247 {
1248 struct ldb_context *ldb;
1249 const char *rdn_name;
1250
1251 ldb = ldb_module_get_ctx(module);
1252 rdn_name = ldb_dn_get_rdn_name(dn);
1253
1254 if (strcasecmp(rdn_name, "cn") != 0) {
1255 ldb_asprintf_errstring(ldb,
1256 "Bad RDN (%s=) for samldb object, "
1257 "should be CN=!\n", rdn_name);
1258 return LDB_ERR_CONSTRAINT_VIOLATION;
1259 }
1260
1261 return LDB_SUCCESS;
1262 }
1263
1264 /* add_record */
1265 static int samldb_add(struct ldb_module *module, struct ldb_request *req)
/* [<][>][^][v][top][bottom][index][help] */
1266 {
1267 struct ldb_context *ldb;
1268 struct samldb_ctx *ac;
1269 int ret;
1270
1271 ldb = ldb_module_get_ctx(module);
1272 ldb_debug(ldb, LDB_DEBUG_TRACE, "samldb_add_record\n");
1273
1274 /* do not manipulate our control entries */
1275 if (ldb_dn_is_special(req->op.add.message->dn)) {
1276 return ldb_next_request(module, req);
1277 }
1278
1279 ac = samldb_ctx_init(module, req);
1280 if (ac == NULL) {
1281 return LDB_ERR_OPERATIONS_ERROR;
1282 }
1283
1284 /* build the new msg */
1285 ac->msg = ldb_msg_copy(ac, ac->req->op.add.message);
1286 if (!ac->msg) {
1287 talloc_free(ac);
1288 ldb_debug(ldb, LDB_DEBUG_FATAL,
1289 "samldb_add: ldb_msg_copy failed!\n");
1290 return LDB_ERR_OPERATIONS_ERROR;
1291 }
1292
1293 if (samdb_find_attribute(ldb, ac->msg,
1294 "objectclass", "computer") != NULL) {
1295
1296 /* make sure the computer object also has the 'user'
1297 * objectclass so it will be handled by the next call */
1298 ret = samdb_find_or_add_value(ldb, ac->msg,
1299 "objectclass", "user");
1300 if (ret != LDB_SUCCESS) {
1301 talloc_free(ac);
1302 return ret;
1303 }
1304 }
1305
1306 if (samdb_find_attribute(ldb, ac->msg,
1307 "objectclass", "user") != NULL) {
1308
1309 ret = samldb_check_rdn(module, ac->req->op.add.message->dn);
1310 if (ret != LDB_SUCCESS) {
1311 talloc_free(ac);
1312 return ret;
1313 }
1314
1315 return samldb_fill_object(ac, "user");
1316 }
1317
1318 if (samdb_find_attribute(ldb, ac->msg,
1319 "objectclass", "group") != NULL) {
1320
1321 ret = samldb_check_rdn(module, ac->req->op.add.message->dn);
1322 if (ret != LDB_SUCCESS) {
1323 talloc_free(ac);
1324 return ret;
1325 }
1326
1327 return samldb_fill_object(ac, "group");
1328 }
1329
1330 /* perhaps a foreignSecurityPrincipal? */
1331 if (samdb_find_attribute(ldb, ac->msg,
1332 "objectclass",
1333 "foreignSecurityPrincipal") != NULL) {
1334
1335 ret = samldb_check_rdn(module, ac->req->op.add.message->dn);
1336 if (ret != LDB_SUCCESS) {
1337 talloc_free(ac);
1338 return ret;
1339 }
1340
1341 return samldb_fill_foreignSecurityPrincipal_object(ac);
1342 }
1343
1344 talloc_free(ac);
1345
1346 /* nothing matched, go on */
1347 return ldb_next_request(module, req);
1348 }
1349
1350 /* modify */
1351 static int samldb_modify(struct ldb_module *module, struct ldb_request *req)
/* [<][>][^][v][top][bottom][index][help] */
1352 {
1353 struct ldb_context *ldb;
1354 struct ldb_message *msg;
1355 struct ldb_message_element *el, *el2;
1356 int ret;
1357 unsigned int group_type, user_account_control, account_type;
1358 if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
1359 return ldb_next_request(module, req);
1360 }
1361
1362 ldb = ldb_module_get_ctx(module);
1363
1364 if (ldb_msg_find_element(req->op.mod.message, "sAMAccountType") != NULL) {
1365 ldb_asprintf_errstring(ldb, "sAMAccountType must not be specified");
1366 return LDB_ERR_UNWILLING_TO_PERFORM;
1367 }
1368
1369 /* TODO: do not modify original request, create a new one */
1370
1371 el = ldb_msg_find_element(req->op.mod.message, "groupType");
1372 if (el && el->flags & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE) && el->num_values == 1) {
1373 req->op.mod.message = msg = ldb_msg_copy_shallow(req, req->op.mod.message);
1374
1375 group_type = strtoul((const char *)el->values[0].data, NULL, 0);
1376 account_type = samdb_gtype2atype(group_type);
1377 ret = samdb_msg_add_uint(ldb, msg, msg,
1378 "sAMAccountType",
1379 account_type);
1380 if (ret != LDB_SUCCESS) {
1381 return ret;
1382 }
1383 el2 = ldb_msg_find_element(msg, "sAMAccountType");
1384 el2->flags = LDB_FLAG_MOD_REPLACE;
1385 }
1386
1387 el = ldb_msg_find_element(req->op.mod.message, "userAccountControl");
1388 if (el && el->flags & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE) && el->num_values == 1) {
1389 req->op.mod.message = msg = ldb_msg_copy_shallow(req, req->op.mod.message);
1390
1391 user_account_control = strtoul((const char *)el->values[0].data, NULL, 0);
1392 account_type = samdb_uf2atype(user_account_control);
1393 ret = samdb_msg_add_uint(ldb, msg, msg,
1394 "sAMAccountType",
1395 account_type);
1396 if (ret != LDB_SUCCESS) {
1397 return ret;
1398 }
1399 el2 = ldb_msg_find_element(msg, "sAMAccountType");
1400 el2->flags = LDB_FLAG_MOD_REPLACE;
1401 }
1402 return ldb_next_request(module, req);
1403 }
1404
1405
1406 static int samldb_init(struct ldb_module *module)
/* [<][>][^][v][top][bottom][index][help] */
1407 {
1408 return ldb_next_init(module);
1409 }
1410
1411 _PUBLIC_ const struct ldb_module_ops ldb_samldb_module_ops = {
1412 .name = "samldb",
1413 .init_context = samldb_init,
1414 .add = samldb_add,
1415 .modify = samldb_modify
1416 };