4 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007
5 Copyright (C) Simo Sorce <idra@samba.org> 2008
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 * Component: ldb linked_attributes module
26 * Description: Module to ensure linked attribute pairs remain in sync
28 * Author: Andrew Bartlett
32 #include "ldb_module.h"
33 #include "dlinklist.h"
34 #include "dsdb/samdb/samdb.h"
35 #include "librpc/gen_ndr/ndr_misc.h"
36 #include "dsdb/samdb/ldb_modules/util.h"
39 static int linked_attributes_fix_links(struct ldb_module
*module
,
40 struct ldb_dn
*old_dn
, struct ldb_dn
*new_dn
,
41 struct ldb_message_element
*el
, struct dsdb_schema
*schema
,
42 const struct dsdb_attribute
*schema_attr
)
45 TALLOC_CTX
*tmp_ctx
= talloc_new(module
);
46 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
47 const struct dsdb_attribute
*target
;
50 target
= dsdb_attribute_by_linkID(schema
, schema_attr
->linkID
^ 1);
52 /* there is no counterpart link to change */
56 attrs
[0] = target
->lDAPDisplayName
;
59 for (i
=0; i
<el
->num_values
; i
++) {
60 struct dsdb_dn
*dsdb_dn
;
63 struct ldb_result
*res
;
64 struct ldb_message
*msg
;
65 struct ldb_message_element
*el2
;
67 dsdb_dn
= dsdb_dn_parse(tmp_ctx
, ldb
, &el
->values
[i
], schema_attr
->syntax
->ldap_oid
);
68 if (dsdb_dn
== NULL
) {
70 return LDB_ERR_INVALID_DN_SYNTAX
;
73 ret
= dsdb_module_search_dn(module
, tmp_ctx
, &res
, dsdb_dn
->dn
,
75 DSDB_SEARCH_SHOW_DELETED
|
76 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT
|
77 DSDB_SEARCH_REVEAL_INTERNALS
);
78 if (ret
!= LDB_SUCCESS
) {
79 ldb_asprintf_errstring(ldb
, "Linked attribute %s->%s between %s and %s - remote not found - %s",
80 el
->name
, target
->lDAPDisplayName
,
81 ldb_dn_get_linearized(old_dn
),
82 ldb_dn_get_linearized(dsdb_dn
->dn
),
89 if (msg
->num_elements
!= 1 ||
90 ldb_attr_cmp(msg
->elements
[0].name
, target
->lDAPDisplayName
) != 0) {
91 ldb_set_errstring(ldb
, "Bad msg elements in linked_attributes_fix_links");
93 return LDB_ERR_OPERATIONS_ERROR
;
95 el2
= &msg
->elements
[0];
97 el2
->flags
= LDB_FLAG_MOD_REPLACE
;
99 /* find our DN in the values */
100 for (j
=0; j
<el2
->num_values
; j
++) {
101 struct dsdb_dn
*dsdb_dn2
;
102 dsdb_dn2
= dsdb_dn_parse(msg
, ldb
, &el2
->values
[j
], target
->syntax
->ldap_oid
);
103 if (dsdb_dn2
== NULL
) {
104 talloc_free(tmp_ctx
);
105 return LDB_ERR_INVALID_DN_SYNTAX
;
107 if (ldb_dn_compare(old_dn
, dsdb_dn2
->dn
) != 0) {
110 ret
= ldb_dn_update_components(dsdb_dn2
->dn
, new_dn
);
111 if (ret
!= LDB_SUCCESS
) {
112 talloc_free(tmp_ctx
);
116 el2
->values
[j
] = data_blob_string_const(
117 dsdb_dn_get_extended_linearized(el2
->values
, dsdb_dn2
, 1));
120 ret
= dsdb_check_single_valued_link(target
, el2
);
121 if (ret
!= LDB_SUCCESS
) {
122 talloc_free(tmp_ctx
);
126 ret
= dsdb_module_modify(module
, msg
, DSDB_MODIFY_RELAX
);
127 if (ret
!= LDB_SUCCESS
) {
128 ldb_asprintf_errstring(ldb
, "Linked attribute %s->%s between %s and %s - update failed - %s",
129 el
->name
, target
->lDAPDisplayName
,
130 ldb_dn_get_linearized(old_dn
),
131 ldb_dn_get_linearized(dsdb_dn
->dn
),
133 talloc_free(tmp_ctx
);
138 talloc_free(tmp_ctx
);
144 static int linked_attributes_rename(struct ldb_module
*module
, struct ldb_request
*req
)
146 struct ldb_result
*res
;
147 struct ldb_message
*msg
;
150 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
151 struct dsdb_schema
*schema
;
153 - load the current msg
154 - find any linked attributes
155 - if its a link then find the target object
156 - modify the target linked attributes with the new DN
158 ret
= dsdb_module_search_dn(module
, req
, &res
, req
->op
.rename
.olddn
,
159 NULL
, DSDB_SEARCH_SHOW_DELETED
);
160 if (ret
!= LDB_SUCCESS
) {
164 schema
= dsdb_get_schema(ldb
, res
);
167 return LDB_ERR_OPERATIONS_ERROR
;
172 for (i
=0; i
<msg
->num_elements
; i
++) {
173 struct ldb_message_element
*el
= &msg
->elements
[i
];
174 const struct dsdb_attribute
*schema_attr
175 = dsdb_attribute_by_lDAPDisplayName(schema
, el
->name
);
176 if (!schema_attr
|| schema_attr
->linkID
== 0) {
179 ret
= linked_attributes_fix_links(module
, msg
->dn
, req
->op
.rename
.newdn
, el
,
180 schema
, schema_attr
);
181 if (ret
!= LDB_SUCCESS
) {
189 return ldb_next_request(module
, req
);
193 _PUBLIC_
const struct ldb_module_ops ldb_linked_attributes_module_ops
= {
194 .name
= "linked_attributes",
195 .rename
= linked_attributes_rename
,