4 Copyright (C) Simo Sorce 2004
6 ** NOTE! The following LGPL license applies to the ldb
7 ** library. This does NOT imply that all of Samba is released
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either
13 version 2 of the License, or (at your option) any later version.
15 This library 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 GNU
18 Lesser General Public License for more details.
20 You should have received a copy of the GNU Lesser General Public
21 License along with this library; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 * Component: ldb samldb module
30 * Description: add object timestamping functionality
36 #include "lib/ldb/include/ldb.h"
37 #include "lib/ldb/include/ldb_private.h"
40 #define SAM_ACCOUNT_NAME_BASE "$000000-000000000000"
43 const char *error_string
;
46 static int samldb_search(struct ldb_module
*module
, const char *base
,
47 enum ldb_scope scope
, const char *expression
,
48 const char * const *attrs
, struct ldb_message
***res
)
50 ldb_debug(module
->ldb
, LDB_DEBUG_TRACE
, "samldb_search\n");
51 return ldb_next_search(module
, base
, scope
, expression
, attrs
, res
);
54 static int samldb_search_free(struct ldb_module
*module
, struct ldb_message
**res
)
56 ldb_debug(module
->ldb
, LDB_DEBUG_TRACE
, "samldb_search_free\n");
57 return ldb_next_search_free(module
, res
);
60 static char *samldb_generate_samAccountName(const void *mem_ctx
) {
63 name
= talloc_strdup(mem_ctx
, SAM_ACCOUNT_NAME_BASE
);
64 /* TODO: randomize name */
69 static BOOL
samldb_get_rdn_and_basedn(const void *mem_ctx
, const char *dn
, char **rdn
, char **basedn
)
80 *rdn
= talloc_strdup(mem_ctx
, dn
);
82 /* put back separator */
89 *basedn
= talloc_strdup(mem_ctx
, p
+ 1);
100 /* if value is not null also check for attribute to have exactly that value */
101 static struct ldb_message_element
*samldb_find_attribute(const struct ldb_message
*msg
, const char *name
, const char *value
)
105 for (i
= 0; i
< msg
->num_elements
; i
++) {
106 if (ldb_attr_cmp(name
, msg
->elements
[i
].name
) == 0) {
108 return &msg
->elements
[i
];
110 for (j
= 0; j
< msg
->elements
[i
].num_values
; j
++) {
111 if (strcasecmp(value
, msg
->elements
[i
].values
[j
].data
) == 0) {
112 return &msg
->elements
[i
];
121 static BOOL
samldb_add_attribute(struct ldb_message
*msg
, const char *name
, const char *value
)
123 struct ldb_message_element
*attr
;
126 attr
= samldb_find_attribute(msg
, name
, NULL
);
129 msg
->elements
= talloc_realloc(msg
, msg
->elements
, struct ldb_message_element
, msg
->num_elements
);
130 if ( ! msg
->elements
) {
133 attr
= &msg
->elements
[msg
->num_elements
- 1];
135 attr
->name
= talloc_strdup(msg
, name
);
136 if ( ! attr
->name
) {
140 attr
->num_values
= 0;
144 i
= attr
->num_values
;
146 attr
->values
= talloc_realloc(msg
, attr
->values
, struct ldb_val
, attr
->num_values
);
147 if ( ! attr
->values
){
151 attr
->values
[i
].data
= talloc_strdup(msg
, value
);
152 attr
->values
[i
].length
= strlen(value
);
154 if ( ! attr
->values
[i
].data
) {
161 static BOOL
samldb_find_or_add_attribute(struct ldb_message
*msg
, const char *name
, const char *value
, const char *set_value
)
163 if (samldb_find_attribute(msg
, name
, value
) == NULL
) {
164 if ( ! samldb_add_attribute(msg
, name
, set_value
)) {
171 static struct ldb_message
*samldb_manage_group_object(struct ldb_module
*module
, const struct ldb_message
*msg
)
173 struct ldb_message
*msg2
;
174 struct ldb_message_element
*attribute
;
178 if (samldb_find_attribute(msg
, "objectclass", "group") == NULL
) {
182 msg2
= talloc(module
, struct ldb_message
);
184 ldb_debug(module
->ldb
, LDB_DEBUG_FATAL
, "samldb_manage_group_object: talloc failed!\n");
188 /* build the new msg */
190 msg2
->num_elements
= msg
->num_elements
;
191 msg2
->private_data
= msg
->private_data
;
192 msg2
->elements
= talloc_array(msg2
, struct ldb_message_element
, msg2
->num_elements
);
193 if (! msg2
->elements
) {
194 ldb_debug(module
->ldb
, LDB_DEBUG_FATAL
, "samldb_manage_group_object: talloc_array failed!\n");
198 for (i
= 0; i
< msg2
->num_elements
; i
++) {
199 msg2
->elements
[i
] = msg
->elements
[i
];
202 if ( ! samldb_get_rdn_and_basedn(msg2
, msg2
->dn
, &rdn
, &basedn
)) {
206 if (strncasecmp(rdn
, "cn", 2) != 0) {
207 ldb_debug(module
->ldb
, LDB_DEBUG_FATAL
, "samldb_manage_group_object: Bad RDN (%s) for group!\n", rdn
);
212 if (! samldb_find_or_add_attribute(msg2
, "objectclass", "top", "top")) {
217 if ((attribute
= samldb_find_attribute(msg2
, "cn", NULL
)) != NULL
) {
218 if (strcasecmp(rdn
, attribute
->values
[0].data
) != 0) {
219 ldb_debug(module
->ldb
, LDB_DEBUG_FATAL
, "samldb_manage_group_object: Bad Attribute Syntax for CN\n");
223 } else { /* FIXME: remove this if ldb supports natively aliasing between the rdn and the "cn" attribute */
224 if ( ! samldb_add_attribute(msg2
, "cn", &rdn
[3])) {
230 if ((attribute
= samldb_find_attribute(msg2
, "name", NULL
)) != NULL
) {
231 if (strcasecmp(rdn
, attribute
->values
[0].data
) != 0) {
232 ldb_debug(module
->ldb
, LDB_DEBUG_FATAL
, "samldb_manage_group_object: Bad Attribute Syntax for name\n");
236 } else { /* FIXME: remove this if ldb supports natively aliasing between the rdn and the "name" attribute */
237 if ( ! samldb_add_attribute(msg2
, "name", &rdn
[3])) {
243 if ( ! samldb_find_or_add_attribute(msg2
, "instanceType", NULL
, "4")) {
247 if ( ! samldb_find_or_add_attribute(msg2
, "sAMAccountName", NULL
, samldb_generate_samAccountName(msg2
))) {
251 if ( ! samldb_find_or_add_attribute(msg2
, "sAMAccountType", NULL
, "268435456")) {
255 if ( ! samldb_find_or_add_attribute(msg2
, "groupType", NULL
, "-2147483646")) {
259 if ( ! samldb_find_or_add_attribute(msg2
, "objectCategory", NULL
, "foo")) { /* keep the schema module happy :) */
263 if ( ! samldb_find_or_add_attribute(msg2
, "objectSid", NULL
, "foo")) { /* keep the schema module happy :) */
267 /* TODO: objectGUID, objectSid, objectCategory */
268 /* need a way to lock a new Sid */
273 static struct ldb_message
*samldb_manage_user_object(struct ldb_module
*module
, const struct ldb_message
*msg
)
275 struct ldb_message
*msg2
;
276 struct ldb_message_element
*attribute
;
280 if (samldb_find_attribute(msg
, "objectclass", "user") == NULL
) {
284 msg2
= talloc(module
, struct ldb_message
);
286 ldb_debug(module
->ldb
, LDB_DEBUG_FATAL
, "samldb_manage_user_object: talloc failed!\n");
290 /* build the new msg */
292 msg2
->num_elements
= msg
->num_elements
;
293 msg2
->private_data
= msg
->private_data
;
294 msg2
->elements
= talloc_array(msg2
, struct ldb_message_element
, msg2
->num_elements
);
295 if (! msg2
->elements
) {
296 ldb_debug(module
->ldb
, LDB_DEBUG_FATAL
, "samldb_manage_user_object: talloc_array failed!\n");
300 for (i
= 0; i
< msg2
->num_elements
; i
++) {
301 msg2
->elements
[i
] = msg
->elements
[i
];
304 if ( ! samldb_get_rdn_and_basedn(msg2
, msg2
->dn
, &rdn
, &basedn
)) {
308 if (strncasecmp(rdn
, "cn", 2) != 0) {
309 ldb_debug(module
->ldb
, LDB_DEBUG_FATAL
, "samldb_manage_group_object: Bad RDN (%s) for group!\n", rdn
);
315 if ( ! samldb_find_or_add_attribute(msg2
, "objectclass", "top", "top")) {
320 if ( ! samldb_find_or_add_attribute(msg2
, "objectclass", "person", "person")) {
325 if ( ! samldb_find_or_add_attribute(msg2
, "objectclass", "organizationalPerson", "organizationalPerson")) {
330 if ((attribute
= samldb_find_attribute(msg2
, "cn", NULL
)) != NULL
) {
331 if (strcasecmp(rdn
, attribute
->values
[0].data
) != 0) {
332 ldb_debug(module
->ldb
, LDB_DEBUG_FATAL
, "samldb_manage_user_object: Bad Attribute Syntax for CN\n");
336 } else { /* FIXME: remove this if ldb supports natively aliasing between the rdn and the "cn" attribute */
337 if ( ! samldb_add_attribute(msg2
, "cn", &rdn
[3])) {
343 if ((attribute
= samldb_find_attribute(msg2
, "name", NULL
)) != NULL
) {
344 if (strcasecmp(rdn
, attribute
->values
[0].data
) != 0) {
345 ldb_debug(module
->ldb
, LDB_DEBUG_FATAL
, "samldb_manage_user_object: Bad Attribute Syntax for name\n");
349 } else { /* FIXME: remove this if ldb supports natively aliasing between the rdn and the "name" attribute */
350 if ( ! samldb_add_attribute(msg2
, "name", &rdn
[3])) {
356 if ( ! samldb_find_or_add_attribute(msg2
, "instanceType", NULL
, "4")) {
361 if ( ! samldb_find_or_add_attribute(msg2
, "sAMAccountName", NULL
, samldb_generate_samAccountName(msg2
))) {
366 if ( ! samldb_find_or_add_attribute(msg2
, "sAMAccountType", NULL
, "805306368")) {
371 if ( ! samldb_find_or_add_attribute(msg2
, "objectCategory", NULL
, "foo")) { /* keep the schema module happy :) */
375 if ( ! samldb_find_or_add_attribute(msg2
, "objectSid", NULL
, "foo")) { /* keep the schema module happy :) */
379 /* TODO: objectGUID, objectSid, objectCategory, userAccountControl, badPwdCount, codePage, countryCode, badPasswordTime, lastLogoff, lastLogon, pwdLastSet, primaryGroupID, accountExpires, logonCount */
385 static int samldb_add_record(struct ldb_module
*module
, const struct ldb_message
*msg
)
387 struct ldb_message
*msg2
= NULL
;
390 ldb_debug(module
->ldb
, LDB_DEBUG_TRACE
, "samldb_add_record\n");
392 if (msg
->dn
[0] == '@') { /* do not manipulate our control entries */
393 return ldb_next_add_record(module
, msg
);
396 /* is group? add all group relevant missing objects */
397 msg2
= samldb_manage_group_object(module
, msg
);
399 /* is user? add all user relevant missing objects */
401 msg2
= samldb_manage_user_object(module
, msg
);
405 ret
= ldb_next_add_record(module
, msg2
);
408 ret
= ldb_next_add_record(module
, msg
);
414 /* modify_record: change modifyTimestamp as well */
415 static int samldb_modify_record(struct ldb_module
*module
, const struct ldb_message
*msg
)
417 ldb_debug(module
->ldb
, LDB_DEBUG_TRACE
, "samldb_modify_record\n");
418 return ldb_next_modify_record(module
, msg
);
421 static int samldb_delete_record(struct ldb_module
*module
, const char *dn
)
423 ldb_debug(module
->ldb
, LDB_DEBUG_TRACE
, "samldb_delete_record\n");
424 return ldb_next_delete_record(module
, dn
);
427 static int samldb_rename_record(struct ldb_module
*module
, const char *olddn
, const char *newdn
)
429 ldb_debug(module
->ldb
, LDB_DEBUG_TRACE
, "samldb_rename_record\n");
430 return ldb_next_rename_record(module
, olddn
, newdn
);
433 static int samldb_lock(struct ldb_module
*module
, const char *lockname
)
435 ldb_debug(module
->ldb
, LDB_DEBUG_TRACE
, "samldb_lock\n");
436 return ldb_next_named_lock(module
, lockname
);
439 static int samldb_unlock(struct ldb_module
*module
, const char *lockname
)
441 ldb_debug(module
->ldb
, LDB_DEBUG_TRACE
, "samldb_unlock\n");
442 return ldb_next_named_unlock(module
, lockname
);
445 /* return extended error information */
446 static const char *samldb_errstring(struct ldb_module
*module
)
448 struct private_data
*data
= (struct private_data
*)module
->private_data
;
450 ldb_debug(module
->ldb
, LDB_DEBUG_TRACE
, "samldb_errstring\n");
451 if (data
->error_string
) {
454 error
= data
->error_string
;
455 data
->error_string
= NULL
;
459 return ldb_next_errstring(module
);
462 static int samldb_destructor(void *module_ctx
)
464 struct ldb_module
*ctx
= module_ctx
;
465 /* put your clean-up functions here */
469 static const struct ldb_module_ops samldb_ops
= {
474 samldb_modify_record
,
475 samldb_delete_record
,
476 samldb_rename_record
,
483 /* the init function */
484 #ifdef HAVE_DLOPEN_DISABLED
485 struct ldb_module
*init_module(struct ldb_context
*ldb
, const char *options
[])
487 struct ldb_module
*samldb_module_init(struct ldb_context
*ldb
, const char *options
[])
490 struct ldb_module
*ctx
;
491 struct private_data
*data
;
493 ctx
= talloc(ldb
, struct ldb_module
);
497 data
= talloc(ctx
, struct private_data
);
503 data
->error_string
= NULL
;
504 ctx
->private_data
= data
;
506 ctx
->prev
= ctx
->next
= NULL
;
507 ctx
->ops
= &samldb_ops
;
509 talloc_set_destructor(ctx
, samldb_destructor
);