2 Unix SMB/CIFS implementation.
3 Infrastructure for async ldap client requests
4 Copyright (C) Volker Lendecke 2009
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 bool tldap_entry_values(struct tldap_message
*msg
, const char *attribute
,
23 int *num_values
, DATA_BLOB
**values
)
25 struct tldap_attribute
*attributes
;
26 int i
, num_attributes
;
28 if (!tldap_entry_attributes(msg
, &num_attributes
, &attributes
)) {
32 for (i
=0; i
<num_attributes
; i
++) {
33 if (strequal(attribute
, attributes
[i
].name
)) {
37 if (i
== num_attributes
) {
40 *num_values
= attributes
[i
].num_values
;
41 *values
= attributes
[i
].values
;
45 bool tldap_get_single_valueblob(struct tldap_message
*msg
,
46 const char *attribute
, DATA_BLOB
*blob
)
51 if (attribute
== NULL
) {
54 if (!tldap_entry_values(msg
, attribute
, &num_values
, &values
)) {
57 if (num_values
!= 1) {
64 char *tldap_talloc_single_attribute(struct tldap_message
*msg
,
65 const char *attribute
,
72 if (!tldap_get_single_valueblob(msg
, attribute
, &val
)) {
75 if (!convert_string_talloc(mem_ctx
, CH_UTF8
, CH_UNIX
,
77 &result
, &len
, false)) {
83 bool tldap_pull_binsid(struct tldap_message
*msg
, const char *attribute
,
88 if (!tldap_get_single_valueblob(msg
, attribute
, &val
)) {
91 return sid_parse((char *)val
.data
, val
.length
, sid
);
94 static bool tldap_add_blob_vals(TALLOC_CTX
*mem_ctx
, struct tldap_mod
*mod
,
95 int num_newvals
, DATA_BLOB
*newvals
)
97 int num_values
= talloc_array_length(mod
->values
);
101 tmp
= talloc_realloc(mem_ctx
, mod
->values
, DATA_BLOB
,
102 num_values
+ num_newvals
);
108 for (i
=0; i
<num_newvals
; i
++) {
109 mod
->values
[i
+num_values
].data
= (uint8_t *)talloc_memdup(
110 mod
->values
, newvals
[i
].data
, newvals
[i
].length
);
111 if (mod
->values
[i
+num_values
].data
== NULL
) {
114 mod
->values
[i
+num_values
].length
= newvals
[i
].length
;
116 mod
->num_values
= num_values
+ num_newvals
;
120 bool tldap_add_mod_blobs(TALLOC_CTX
*mem_ctx
, struct tldap_mod
**pmods
,
121 int mod_op
, const char *attrib
,
122 int num_newvals
, DATA_BLOB
*newvals
)
124 struct tldap_mod new_mod
;
125 struct tldap_mod
*mods
= *pmods
;
126 struct tldap_mod
*mod
= NULL
;
130 mods
= talloc_array(mem_ctx
, struct tldap_mod
, 0);
136 num_mods
= talloc_array_length(mods
);
138 for (i
=0; i
<num_mods
; i
++) {
139 if ((mods
[i
].mod_op
== mod_op
)
140 && strequal(mods
[i
].attribute
, attrib
)) {
147 new_mod
.mod_op
= mod_op
;
148 new_mod
.attribute
= talloc_strdup(mods
, attrib
);
149 if (new_mod
.attribute
== NULL
) {
152 new_mod
.num_values
= 0;
153 new_mod
.values
= NULL
;
157 if ((num_newvals
!= 0)
158 && !tldap_add_blob_vals(mods
, mod
, num_newvals
, newvals
)) {
163 mods
= talloc_realloc(talloc_tos(), mods
, struct tldap_mod
,
168 mods
[num_mods
] = *mod
;
175 static bool tldap_make_mod_blob_int(struct tldap_message
*existing
,
177 int *pnum_mods
, struct tldap_mod
**pmods
,
178 const char *attrib
, DATA_BLOB newval
,
179 int (*comparison
)(const DATA_BLOB
*d1
,
180 const DATA_BLOB
*d2
))
183 DATA_BLOB
*values
= NULL
;
184 DATA_BLOB oldval
= data_blob_null
;
186 if ((existing
!= NULL
)
187 && tldap_entry_values(existing
, attrib
, &num_values
, &values
)) {
189 if (num_values
> 1) {
190 /* can't change multivalue attributes atm */
193 if (num_values
== 1) {
198 if ((oldval
.data
!= NULL
) && (newval
.data
!= NULL
)
199 && (comparison(&oldval
, &newval
) == 0)) {
200 /* Believe it or not, but LDAP will deny a delete and
201 an add at the same time if the values are the
203 DEBUG(10,("smbldap_make_mod_blob: attribute |%s| not "
204 "changed.\n", attrib
));
208 if (oldval
.data
!= NULL
) {
209 /* By deleting exactly the value we found in the entry this
210 * should be race-free in the sense that the LDAP-Server will
211 * deny the complete operation if somebody changed the
212 * attribute behind our back. */
213 /* This will also allow modifying single valued attributes in
214 * Novell NDS. In NDS you have to first remove attribute and
215 * then you could add new value */
217 DEBUG(10, ("smbldap_make_mod_blob: deleting attribute |%s|\n",
219 if (!tldap_add_mod_blobs(mem_ctx
, pmods
, TLDAP_MOD_DELETE
,
220 attrib
, 1, &oldval
)) {
225 /* Regardless of the real operation (add or modify)
226 we add the new value here. We rely on deleting
227 the old value, should it exist. */
229 if (newval
.data
!= NULL
) {
230 DEBUG(10, ("smbldap_make_mod: adding attribute |%s| value len "
231 "%d\n", attrib
, (int)newval
.length
));
232 if (!tldap_add_mod_blobs(mem_ctx
, pmods
, TLDAP_MOD_ADD
,
233 attrib
, 1, &newval
)) {
237 *pnum_mods
= talloc_array_length(*pmods
);
241 bool tldap_make_mod_blob(struct tldap_message
*existing
, TALLOC_CTX
*mem_ctx
,
242 int *pnum_mods
, struct tldap_mod
**pmods
,
243 const char *attrib
, DATA_BLOB newval
)
245 return tldap_make_mod_blob_int(existing
, mem_ctx
, pnum_mods
, pmods
,
246 attrib
, newval
, data_blob_cmp
);
249 static int compare_utf8_blobs(const DATA_BLOB
*d1
, const DATA_BLOB
*d2
)
255 if (!convert_string_talloc(talloc_tos(), CH_UTF8
, CH_UNIX
, d1
->data
,
256 d1
->length
, &s1
, &s1len
, false)) {
257 /* can't do much here */
260 if (!convert_string_talloc(talloc_tos(), CH_UTF8
, CH_UNIX
, d2
->data
,
261 d2
->length
, &s2
, &s2len
, false)) {
262 /* can't do much here */
266 ret
= StrCaseCmp(s1
, s2
);
272 bool tldap_make_mod_fmt(struct tldap_message
*existing
, TALLOC_CTX
*mem_ctx
,
273 int *pnum_mods
, struct tldap_mod
**pmods
,
274 const char *attrib
, const char *fmt
, ...)
279 DATA_BLOB blob
= data_blob_null
;
282 newval
= talloc_vasprintf(talloc_tos(), fmt
, ap
);
285 if (newval
== NULL
) {
289 blob
.length
= strlen(newval
);
290 if (blob
.length
!= 0) {
291 blob
.data
= CONST_DISCARD(uint8_t *, newval
);
293 ret
= tldap_make_mod_blob_int(existing
, mem_ctx
, pnum_mods
, pmods
,
294 attrib
, blob
, compare_utf8_blobs
);
299 const char *tldap_errstr(TALLOC_CTX
*mem_ctx
, struct tldap_context
*ld
, int rc
)
301 const char *ld_error
= NULL
;
304 ld_error
= tldap_ctx_diagnosticmessage(ld
);
305 res
= talloc_asprintf(mem_ctx
, "LDAP error %d (%s), %s", rc
,
306 tldap_err2string(rc
),
307 ld_error
? ld_error
: "unknown");
311 int tldap_search_fmt(struct tldap_context
*ld
, const char *base
, int scope
,
312 const char *attrs
[], int num_attrs
, int attrsonly
,
313 TALLOC_CTX
*mem_ctx
, struct tldap_message
***res
,
314 const char *fmt
, ...)
321 filter
= talloc_vasprintf(talloc_tos(), fmt
, ap
);
324 if (filter
== NULL
) {
325 return TLDAP_NO_MEMORY
;
327 ret
= tldap_search(ld
, base
, scope
, filter
,
328 attrs
, num_attrs
, attrsonly
,
329 NULL
/*sctrls*/, NULL
/*cctrls*/,
330 0 /*timelimit*/, 0 /*sizelimit*/, 0 /*deref*/,
336 bool tldap_pull_uint64(struct tldap_message
*msg
, const char *attr
,
342 str
= tldap_talloc_single_attribute(msg
, attr
, talloc_tos());
344 DEBUG(10, ("Could not find attribute %s\n", attr
));
347 result
= strtoull(str
, NULL
, 10);