4 Copyright (C) Simo Sorce 2004
5 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
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 v2 or
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 2 of the License, or
14 (at your option) any later version.
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.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 * Component: ldb samldb module
31 * Description: add embedded user/group creation functionality
37 #include "libcli/ldap/ldap.h"
38 #include "lib/ldb/include/ldb_errors.h"
39 #include "lib/ldb/include/ldb_private.h"
40 #include "dsdb/samdb/samdb.h"
41 #include "libcli/security/proto.h"
45 /* if value is not null also check for attribute to have exactly that value */
46 static struct ldb_message_element *samldb_find_attribute(const struct ldb_message *msg, const char *name, const char *value)
49 struct ldb_message_element *el = ldb_msg_find_element(msg, name);
58 for (j = 0; j < el->num_values; j++) {
60 (char *)el->values[j].data) == 0) {
68 static BOOL samldb_msg_add_string(struct ldb_module *module, struct ldb_message *msg, const char *name, const char *value)
70 char *aval = talloc_strdup(msg, value);
73 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_msg_add_string: talloc_strdup failed!\n");
77 if (ldb_msg_add_string(msg, name, aval) != 0) {
84 static BOOL samldb_msg_add_sid(struct ldb_module *module, struct ldb_message *msg, const char *name, const struct dom_sid *sid)
88 status = ndr_push_struct_blob(&v, msg, sid,
89 (ndr_push_flags_fn_t)ndr_push_dom_sid);
90 if (!NT_STATUS_IS_OK(status)) {
93 return (ldb_msg_add_value(msg, name, &v) == 0);
96 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)
98 if (samldb_find_attribute(msg, name, value) == NULL) {
99 return samldb_msg_add_string(module, msg, name, set_value);
105 allocate a new id, attempting to do it atomically
106 return 0 on failure, the id on success
108 static int samldb_set_next_rid(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
109 const struct ldb_dn *dn, uint32_t old_id, uint32_t new_id)
111 struct ldb_message msg;
113 struct ldb_val vals[2];
114 struct ldb_message_element els[2];
118 ldb_debug(ldb, LDB_DEBUG_FATAL, "Are we out of valid IDs ?\n");
119 return LDB_ERR_OPERATIONS_ERROR;
122 /* we do a delete and add as a single operation. That prevents
123 a race, in case we are not actually on a transaction db */
125 msg.dn = ldb_dn_copy(mem_ctx, dn);
127 return LDB_ERR_OPERATIONS_ERROR;
129 msg.num_elements = 2;
132 els[0].num_values = 1;
133 els[0].values = &vals[0];
134 els[0].flags = LDB_FLAG_MOD_DELETE;
135 els[0].name = talloc_strdup(mem_ctx, "nextRid");
137 return LDB_ERR_OPERATIONS_ERROR;
140 els[1].num_values = 1;
141 els[1].values = &vals[1];
142 els[1].flags = LDB_FLAG_MOD_ADD;
143 els[1].name = els[0].name;
145 vals[0].data = (uint8_t *)talloc_asprintf(mem_ctx, "%u", old_id);
147 return LDB_ERR_OPERATIONS_ERROR;
149 vals[0].length = strlen((char *)vals[0].data);
151 vals[1].data = (uint8_t *)talloc_asprintf(mem_ctx, "%u", new_id);
153 return LDB_ERR_OPERATIONS_ERROR;
155 vals[1].length = strlen((char *)vals[1].data);
157 ret = ldb_modify(ldb, &msg);
162 allocate a new id, attempting to do it atomically
163 return 0 on failure, the id on success
165 static int samldb_find_next_rid(struct ldb_module *module, TALLOC_CTX *mem_ctx,
166 const struct ldb_dn *dn, uint32_t *old_rid)
168 const char * const attrs[2] = { "nextRid", NULL };
169 struct ldb_result *res = NULL;
173 ret = ldb_search(module->ldb, dn, LDB_SCOPE_BASE, "nextRid=*", attrs, &res);
174 if (ret != LDB_SUCCESS) {
177 talloc_steal(mem_ctx, res);
178 if (res->count != 1) {
183 str = ldb_msg_find_string(res->msgs[0], "nextRid", NULL);
185 ldb_set_errstring(module->ldb,
186 talloc_asprintf(mem_ctx, "attribute nextRid not found in %s\n",
187 ldb_dn_linearize(res, dn)));
192 *old_rid = strtol(str, NULL, 0);
197 static int samldb_allocate_next_rid(struct ldb_module *module, TALLOC_CTX *mem_ctx,
198 const struct ldb_dn *dn, const struct dom_sid *dom_sid,
199 struct dom_sid **new_sid)
201 struct dom_sid *obj_sid;
204 struct ldb_message **sid_msgs;
205 const char *sid_attrs[] = { NULL };
208 ret = samldb_find_next_rid(module, mem_ctx, dn, &old_rid);
213 /* return the new object sid */
214 obj_sid = dom_sid_add_rid(mem_ctx, dom_sid, old_rid);
216 ret = samldb_set_next_rid(module->ldb, mem_ctx, dn, old_rid, old_rid + 1);
221 *new_sid = dom_sid_add_rid(mem_ctx, dom_sid, old_rid + 1);
223 return LDB_ERR_OPERATIONS_ERROR;
226 ret = gendb_search(module->ldb,
227 mem_ctx, NULL, &sid_msgs, sid_attrs,
229 ldap_encode_ndr_dom_sid(mem_ctx, *new_sid));
231 /* Great. There are no conflicting users/groups/etc */
233 } else if (ret == -1) {
234 /* Bugger, there is a problem, and we don't know what it is until gendb_search improves */
237 /* gah, there are conflicting sids, lets move around the loop again... */
243 /* Find a domain object in the parents of a particular DN. */
244 static struct ldb_dn *samldb_search_domain(struct ldb_module *module, TALLOC_CTX *mem_ctx, const struct ldb_dn *dn)
246 TALLOC_CTX *local_ctx;
248 struct ldb_result *res = NULL;
251 local_ctx = talloc_new(mem_ctx);
252 if (local_ctx == NULL) return NULL;
254 sdn = ldb_dn_copy(local_ctx, dn);
256 ret = ldb_search(module->ldb, sdn, LDB_SCOPE_BASE, "objectClass=domain", NULL, &res);
257 talloc_steal(local_ctx, res);
258 if (ret == LDB_SUCCESS && res->count == 1)
260 } while ((sdn = ldb_dn_get_parent(local_ctx, sdn)));
262 if (ret != LDB_SUCCESS || res->count != 1) {
263 talloc_free(local_ctx);
267 talloc_steal(mem_ctx, sdn);
268 talloc_free(local_ctx);
273 /* search the domain related to the provided dn
274 allocate a new RID for the domain
275 return the new sid string
277 static struct dom_sid *samldb_get_new_sid(struct ldb_module *module,
278 TALLOC_CTX *mem_ctx, const struct ldb_dn *obj_dn)
280 const char * const attrs[2] = { "objectSid", NULL };
281 struct ldb_result *res = NULL;
282 const struct ldb_dn *dom_dn;
284 struct dom_sid *dom_sid, *obj_sid;
286 /* get the domain component part of the provided dn */
288 dom_dn = samldb_search_domain(module, mem_ctx, obj_dn);
289 if (dom_dn == NULL) {
290 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Invalid dn (%s) not child of a domain object!\n", ldb_dn_linearize(mem_ctx, obj_dn));
294 /* find the domain sid */
296 ret = ldb_search(module->ldb, dom_dn, LDB_SCOPE_BASE, "objectSid=*", attrs, &res);
297 if (ret != LDB_SUCCESS || res->count != 1) {
298 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_get_new_sid: error retrieving domain sid!\n");
303 dom_sid = samdb_result_dom_sid(res, res->msgs[0], "objectSid");
304 if (dom_sid == NULL) {
305 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_get_new_sid: error retrieving domain sid!\n");
310 /* allocate a new Rid for the domain */
311 ret = samldb_allocate_next_rid(module, mem_ctx, dom_dn, dom_sid, &obj_sid);
313 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Failed to increment nextRid of %s\n", ldb_dn_linearize(mem_ctx, dom_dn));
323 /* If we are adding new users/groups, we need to update the nextRid
324 * attribute to be 'above' all incoming users RIDs. This tries to
325 * avoid clashes in future */
327 int samldb_notice_sid(struct ldb_module *module,
328 TALLOC_CTX *mem_ctx, const struct dom_sid *sid)
331 struct ldb_dn *dom_dn;
332 struct dom_sid *dom_sid;
333 const char *dom_attrs[] = { NULL };
334 struct ldb_message **dom_msgs;
337 /* find the domain DN */
339 ret = gendb_search(module->ldb,
340 mem_ctx, NULL, &dom_msgs, dom_attrs,
342 ldap_encode_ndr_dom_sid(mem_ctx, sid));
344 ldb_set_errstring(module->ldb,
345 talloc_asprintf(mem_ctx,
346 "Attempt to add record with SID %s rejected,"
347 " because this SID is already in the database",
348 dom_sid_string(mem_ctx, sid)));
349 /* We have a duplicate SID, we must reject the add */
350 talloc_free(dom_msgs);
351 return LDB_ERR_CONSTRAINT_VIOLATION;
355 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_get_new_sid: error searching for proposed sid!\n");
359 dom_sid = dom_sid_dup(mem_ctx, sid);
361 return LDB_ERR_OPERATIONS_ERROR;
363 /* get the domain component part of the provided SID */
364 dom_sid->num_auths--;
366 /* find the domain DN */
368 ret = gendb_search(module->ldb,
369 mem_ctx, NULL, &dom_msgs, dom_attrs,
370 "(&(objectSid=%s)(objectclass=domain))",
371 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid));
373 /* This isn't an operation on a domain we know about, so nothing to update */
378 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_get_new_sid: error retrieving domain from sid: duplicate domains!\n");
379 talloc_free(dom_msgs);
384 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_get_new_sid: error retrieving domain sid!\n");
388 dom_dn = dom_msgs[0]->dn;
390 ret = samldb_find_next_rid(module, mem_ctx,
393 talloc_free(dom_msgs);
397 if (old_rid <= sid->sub_auths[sid->num_auths - 1]) {
398 ret = samldb_set_next_rid(module->ldb, mem_ctx, dom_dn, old_rid,
399 sid->sub_auths[sid->num_auths - 1] + 1);
401 talloc_free(dom_msgs);
405 static int samldb_handle_sid(struct ldb_module *module,
406 TALLOC_CTX *mem_ctx, struct ldb_message *msg2)
410 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg2, "objectSid");
412 sid = samldb_get_new_sid(module, msg2, msg2->dn);
414 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_user_or_computer_object: internal error! Can't generate new sid\n");
415 return LDB_ERR_OPERATIONS_ERROR;
418 if ( ! samldb_msg_add_sid(module, msg2, "objectSid", sid)) {
420 return LDB_ERR_OPERATIONS_ERROR;
425 ret = samldb_notice_sid(module, msg2, sid);
430 static char *samldb_generate_samAccountName(struct ldb_module *module, TALLOC_CTX *mem_ctx)
433 const char *attrs[] = { NULL };
434 struct ldb_message **msgs;
437 /* Format: $000000-000000000000 */
440 name = talloc_asprintf(mem_ctx, "$%.6X-%.6X%.6X", (unsigned int)random(), (unsigned int)random(), (unsigned int)random());
441 /* TODO: Figure out exactly what this is meant to conflict with */
442 ret = gendb_search(module->ldb,
443 mem_ctx, NULL, &msgs, attrs,
445 ldb_binary_encode_string(mem_ctx, name));
447 /* Great. There are no conflicting users/groups/etc */
449 } else if (ret == -1) {
450 /* Bugger, there is a problem, and we don't know what it is until gendb_search improves */
454 /* gah, there are conflicting sids, lets move around the loop again... */
459 static int samldb_copy_template(struct ldb_module *module, struct ldb_message *msg, const char *filter)
461 struct ldb_result *res;
462 struct ldb_message *t;
466 /* pull the template record */
467 ret = ldb_search(module->ldb, NULL, LDB_SCOPE_SUBTREE, filter, NULL, &res);
468 if (ret != LDB_SUCCESS || res->count != 1) {
469 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "samldb: ERROR: template '%s' matched too many records\n", filter);
474 for (i = 0; i < t->num_elements; i++) {
475 struct ldb_message_element *el = &t->elements[i];
476 /* some elements should not be copied from the template */
477 if (strcasecmp(el->name, "cn") == 0 ||
478 strcasecmp(el->name, "name") == 0 ||
479 strcasecmp(el->name, "sAMAccountName") == 0 ||
480 strcasecmp(el->name, "objectGUID") == 0) {
483 for (j = 0; j < el->num_values; j++) {
484 if (strcasecmp(el->name, "objectClass") == 0) {
485 if (strcasecmp((char *)el->values[j].data, "Template") == 0 ||
486 strcasecmp((char *)el->values[j].data, "userTemplate") == 0 ||
487 strcasecmp((char *)el->values[j].data, "groupTemplate") == 0 ||
488 strcasecmp((char *)el->values[j].data, "foreignSecurityPrincipalTemplate") == 0 ||
489 strcasecmp((char *)el->values[j].data, "aliasTemplate") == 0 ||
490 strcasecmp((char *)el->values[j].data, "trustedDomainTemplate") == 0 ||
491 strcasecmp((char *)el->values[j].data, "secretTemplate") == 0) {
494 if ( ! samldb_find_or_add_attribute(module, msg, el->name,
495 (char *)el->values[j].data,
496 (char *)el->values[j].data)) {
497 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Attribute adding failed...\n");
502 if ( ! samldb_find_or_add_attribute(module, msg, el->name,
504 (char *)el->values[j].data)) {
505 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Attribute adding failed...\n");
518 static int samldb_fill_group_object(struct ldb_module *module, const struct ldb_message *msg,
519 struct ldb_message **ret_msg)
523 struct ldb_message *msg2;
524 struct ldb_dn_component *rdn;
525 TALLOC_CTX *mem_ctx = talloc_new(msg);
527 return LDB_ERR_OPERATIONS_ERROR;
530 /* build the new msg */
531 msg2 = ldb_msg_copy(mem_ctx, msg);
533 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_group_object: ldb_msg_copy failed!\n");
534 talloc_free(mem_ctx);
535 return LDB_ERR_OPERATIONS_ERROR;
538 ret = samldb_copy_template(module, msg2, "(&(CN=TemplateGroup)(objectclass=groupTemplate))");
540 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "samldb_fill_group_object: Error copying template!\n");
541 talloc_free(mem_ctx);
545 rdn = ldb_dn_get_rdn(msg2, msg2->dn);
547 if (strcasecmp(rdn->name, "cn") != 0) {
548 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_group_object: Bad RDN (%s) for group!\n", rdn->name);
549 talloc_free(mem_ctx);
550 return LDB_ERR_CONSTRAINT_VIOLATION;
553 /* Generate a random name, if no samAccountName was supplied */
554 if (ldb_msg_find_element(msg2, "samAccountName") == NULL) {
555 name = samldb_generate_samAccountName(module, mem_ctx);
557 talloc_free(mem_ctx);
558 return LDB_ERR_OPERATIONS_ERROR;
560 if ( ! samldb_find_or_add_attribute(module, msg2, "sAMAccountName", NULL, name)) {
561 talloc_free(mem_ctx);
562 return LDB_ERR_OPERATIONS_ERROR;
566 /* Manage SID allocation, conflicts etc */
567 ret = samldb_handle_sid(module, mem_ctx, msg2);
570 talloc_steal(msg, msg2);
573 talloc_free(mem_ctx);
577 static int samldb_fill_user_or_computer_object(struct ldb_module *module, const struct ldb_message *msg,
578 struct ldb_message **ret_msg)
582 struct ldb_message *msg2;
583 struct ldb_dn_component *rdn;
584 TALLOC_CTX *mem_ctx = talloc_new(msg);
586 return LDB_ERR_OPERATIONS_ERROR;
589 /* build the new msg */
590 msg2 = ldb_msg_copy(mem_ctx, msg);
592 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_group_object: ldb_msg_copy failed!\n");
593 talloc_free(mem_ctx);
594 return LDB_ERR_OPERATIONS_ERROR;
597 if (samldb_find_attribute(msg, "objectclass", "computer") != NULL) {
598 ret = samldb_copy_template(module, msg2, "(&(CN=TemplateComputer)(objectclass=userTemplate))");
600 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "samldb_fill_user_or_computer_object: Error copying computer template!\n");
601 talloc_free(mem_ctx);
605 ret = samldb_copy_template(module, msg2, "(&(CN=TemplateUser)(objectclass=userTemplate))");
607 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "samldb_fill_user_or_computer_object: Error copying user template!\n");
608 talloc_free(mem_ctx);
613 rdn = ldb_dn_get_rdn(msg2, msg2->dn);
615 if (strcasecmp(rdn->name, "cn") != 0) {
616 ldb_set_errstring(module->ldb, talloc_asprintf(module, "Bad RDN (%s=) for user/computer, should be CN=!\n", rdn->name));
617 talloc_free(mem_ctx);
618 return LDB_ERR_CONSTRAINT_VIOLATION;
621 /* if the only attribute was: "objectclass: computer", then make sure we also add "user" objectclass */
622 if ( ! samldb_find_or_add_attribute(module, msg2, "objectclass", "user", "user")) {
623 talloc_free(mem_ctx);
624 return LDB_ERR_OPERATIONS_ERROR;
627 /* meddle with objectclass */
629 if (ldb_msg_find_element(msg2, "samAccountName") == NULL) {
630 name = samldb_generate_samAccountName(module, mem_ctx);
632 talloc_free(mem_ctx);
633 return LDB_ERR_OPERATIONS_ERROR;
635 if ( ! samldb_find_or_add_attribute(module, msg2, "sAMAccountName", NULL, name)) {
636 talloc_free(mem_ctx);
637 return LDB_ERR_OPERATIONS_ERROR;
642 TODO: useraccountcontrol: setting value 0 gives 0x200 for users
645 /* Manage SID allocation, conflicts etc */
646 ret = samldb_handle_sid(module, mem_ctx, msg2);
648 /* TODO: objectCategory, userAccountControl, badPwdCount, codePage, countryCode, badPasswordTime, lastLogoff, lastLogon, pwdLastSet, primaryGroupID, accountExpires, logonCount */
652 talloc_steal(msg, msg2);
654 talloc_free(mem_ctx);
658 static int samldb_fill_foreignSecurityPrincipal_object(struct ldb_module *module, const struct ldb_message *msg,
659 struct ldb_message **ret_msg)
661 struct ldb_message *msg2;
662 struct ldb_dn_component *rdn;
663 struct dom_sid *dom_sid;
665 const char *dom_attrs[] = { "name", NULL };
666 struct ldb_message **dom_msgs;
669 TALLOC_CTX *mem_ctx = talloc_new(msg);
671 return LDB_ERR_OPERATIONS_ERROR;
674 /* build the new msg */
675 msg2 = ldb_msg_copy(mem_ctx, msg);
677 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_foreignSecurityPrincpal_object: ldb_msg_copy failed!\n");
678 talloc_free(mem_ctx);
679 return LDB_ERR_OPERATIONS_ERROR;
682 ret = samldb_copy_template(module, msg2, "(&(CN=TemplateForeignSecurityPrincipal)(objectclass=foreignSecurityPrincipalTemplate))");
684 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "samldb_fill_foreignSecurityPrincipal_object: Error copying template!\n");
685 talloc_free(mem_ctx);
689 rdn = ldb_dn_get_rdn(msg2, msg2->dn);
691 if (strcasecmp(rdn->name, "cn") != 0) {
692 ldb_set_errstring(module->ldb, talloc_asprintf(module, "Bad RDN (%s=) for ForeignSecurityPrincipal, should be CN=!", rdn->name));
693 talloc_free(mem_ctx);
694 return LDB_ERR_CONSTRAINT_VIOLATION;
697 /* Slightly different for the foreign sids. We don't want
698 * domain SIDs ending up there, it would cause all sorts of
701 sid = dom_sid_parse_talloc(msg2, (const char *)rdn->value.data);
703 ldb_set_errstring(module->ldb, talloc_asprintf(module, "No valid found SID in ForeignSecurityPrincipal CN!"));
704 talloc_free(mem_ctx);
705 return LDB_ERR_CONSTRAINT_VIOLATION;
708 if ( ! samldb_msg_add_sid(module, msg2, "objectSid", sid)) {
710 return LDB_ERR_OPERATIONS_ERROR;
713 dom_sid = dom_sid_dup(mem_ctx, sid);
715 talloc_free(mem_ctx);
716 return LDB_ERR_OPERATIONS_ERROR;
718 /* get the domain component part of the provided SID */
719 dom_sid->num_auths--;
721 /* find the domain DN */
723 ret = gendb_search(module->ldb,
724 mem_ctx, NULL, &dom_msgs, dom_attrs,
725 "(&(objectSid=%s)(objectclass=domain))",
726 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid));
728 const char *name = samdb_result_string(dom_msgs[0], "name", NULL);
729 ldb_set_errstring(module->ldb, talloc_asprintf(mem_ctx, "Attempt to add foreign SID record with SID %s rejected, because this domian (%s) is already in the database", dom_sid_string(mem_ctx, sid), name));
730 /* We don't really like the idea of foreign sids that are not foreign */
731 return LDB_ERR_CONSTRAINT_VIOLATION;
732 } else if (ret == -1) {
733 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_foreignSecurityPrincipal_object: error searching for a domain with this sid: %s\n", dom_sid_string(mem_ctx, dom_sid));
734 talloc_free(dom_msgs);
738 /* This isn't an operation on a domain we know about, so just
739 * check for the SID, looking for duplicates via the common
741 ret = samldb_notice_sid(module, msg2, sid);
743 talloc_steal(msg, msg2);
751 static int samldb_add(struct ldb_module *module, struct ldb_request *req)
753 const struct ldb_message *msg = req->op.add.message;
754 struct ldb_message *msg2 = NULL;
757 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "samldb_add_record\n");
760 if (ldb_dn_is_special(msg->dn)) { /* do not manipulate our control entries */
761 return ldb_next_request(module, req);
764 /* is user or computer? add all relevant missing objects */
765 if ((samldb_find_attribute(msg, "objectclass", "user") != NULL) ||
766 (samldb_find_attribute(msg, "objectclass", "computer") != NULL)) {
767 ret = samldb_fill_user_or_computer_object(module, msg, &msg2);
773 /* is group? add all relevant missing objects */
775 if (samldb_find_attribute(msg, "objectclass", "group") != NULL) {
776 ret = samldb_fill_group_object(module, msg, &msg2);
783 /* perhaps a foreignSecurityPrincipal? */
785 if (samldb_find_attribute(msg, "objectclass", "foreignSecurityPrincipal") != NULL) {
786 ret = samldb_fill_foreignSecurityPrincipal_object(module, msg, &msg2);
794 req->op.add.message = msg2;
795 ret = ldb_next_request(module, req);
796 req->op.add.message = msg;
798 ret = ldb_next_request(module, req);
804 static int samldb_destructor(void *module_ctx)
806 /* struct ldb_module *ctx = module_ctx; */
807 /* put your clean-up functions here */
811 static int samldb_request(struct ldb_module *module, struct ldb_request *req)
813 switch (req->operation) {
816 return samldb_add(module, req);
819 return ldb_next_request(module, req);
824 static int samldb_init(struct ldb_module *module)
826 talloc_set_destructor(module, samldb_destructor);
827 return ldb_next_init(module);
830 static const struct ldb_module_ops samldb_ops = {
832 .init_context = samldb_init,
833 .request = samldb_request
837 int samldb_module_init(void)
839 return ldb_register_module(&samldb_ops);