4 Copyright (C) Andrew Tridgell 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: ldbsearch
30 * Description: utility for ldb search - modelled on ldapsearch
32 * Author: Andrew Tridgell
36 #include "ldb/include/includes.h"
37 #include "ldb/tools/cmdline.h"
39 static void usage(void)
41 printf("Usage: ldbsearch <options> <expression> <attrs...>\n");
43 printf(" -H ldb_url choose the database (or $LDB_URL)\n");
44 printf(" -s base|sub|one choose search scope\n");
45 printf(" -b basedn choose baseDN\n");
46 printf(" -i read search expressions from stdin\n");
47 printf(" -S sort returned attributes\n");
48 printf(" -o options pass options like modules to activate\n");
49 printf(" e.g: -o modules:timestamps\n");
53 static int do_compare_msg(struct ldb_message
**el1
,
54 struct ldb_message
**el2
,
57 struct ldb_context
*ldb
= talloc_get_type(opaque
, struct ldb_context
);
58 return ldb_dn_compare(ldb
, (*el1
)->dn
, (*el2
)->dn
);
61 static struct ldb_control
**parse_controls(void *mem_ctx
, char **control_strings
)
64 struct ldb_control
**ctrl
;
66 if (control_strings
== NULL
|| control_strings
[0] == NULL
)
69 for (i
= 0; control_strings
[i
]; i
++);
71 ctrl
= talloc_array(mem_ctx
, struct ldb_control
*, i
+ 1);
73 for (i
= 0; control_strings
[i
]; i
++) {
74 if (strncmp(control_strings
[i
], "extended_dn:", 12) == 0) {
75 struct ldb_extended_dn_control
*control
;
79 p
= &(control_strings
[i
][12]);
80 ret
= sscanf(p
, "%d:%d", &crit
, &type
);
81 if ((ret
!= 2) || (crit
< 0) || (crit
> 1) || (type
< 0) || (type
> 1)) {
82 fprintf(stderr
, "invalid extended_dn control syntax\n");
86 ctrl
[i
] = talloc(ctrl
, struct ldb_control
);
87 ctrl
[i
]->oid
= LDB_CONTROL_EXTENDED_DN_OID
;
88 ctrl
[i
]->critical
= crit
;
89 control
= talloc(ctrl
[i
], struct ldb_extended_dn_control
);
91 ctrl
[i
]->data
= control
;
96 if (strncmp(control_strings
[i
], "paged_results:", 14) == 0) {
97 struct ldb_paged_control
*control
;
101 p
= &(control_strings
[i
][14]);
102 ret
= sscanf(p
, "%d:%d", &crit
, &size
);
104 if ((ret
!= 2) || (crit
< 0) || (crit
> 1) || (size
< 0)) {
105 fprintf(stderr
, "invalid paged_results control syntax\n");
109 ctrl
[i
] = talloc(ctrl
, struct ldb_control
);
110 ctrl
[i
]->oid
= LDB_CONTROL_PAGED_RESULTS_OID
;
111 ctrl
[i
]->critical
= crit
;
112 control
= talloc(ctrl
[i
], struct ldb_paged_control
);
113 control
->size
= size
;
114 control
->cookie
= NULL
;
115 control
->cookie_len
= 0;
116 ctrl
[i
]->data
= control
;
121 if (strncmp(control_strings
[i
], "server_sort:", 12) == 0) {
122 struct ldb_server_sort_control
**control
;
130 p
= &(control_strings
[i
][12]);
131 ret
= sscanf(p
, "%d:%d:%255[^:]:%127[^:]", &crit
, &rev
, attr
, rule
);
132 if ((ret
< 3) || (crit
< 0) || (crit
> 1) || (rev
< 0 ) || (rev
> 1) ||attr
[0] == '\0') {
133 fprintf(stderr
, "invalid server_sort control syntax\n");
136 ctrl
[i
] = talloc(ctrl
, struct ldb_control
);
137 ctrl
[i
]->oid
= LDB_CONTROL_SERVER_SORT_OID
;
138 ctrl
[i
]->critical
= crit
;
139 control
= talloc_array(ctrl
[i
], struct ldb_server_sort_control
*, 2);
140 control
[0] = talloc(control
, struct ldb_server_sort_control
);
141 control
[0]->attributeName
= talloc_strdup(control
, attr
);
143 control
[0]->orderingRule
= talloc_strdup(control
, rule
);
145 control
[0]->orderingRule
= NULL
;
146 control
[0]->reverse
= rev
;
148 ctrl
[i
]->data
= control
;
153 /* no controls matched, throw an error */
154 fprintf(stderr
, "Invalid control name\n");
163 /* this function check controls reply and determines if more
164 * processing is needed setting up the request controls correctly
169 * 1 all ok, more processing required
171 static int handle_controls_reply(struct ldb_control
**reply
, struct ldb_control
**request
)
176 if (reply
== NULL
|| request
== NULL
) return -1;
178 for (i
= 0; reply
[i
]; i
++) {
179 if (strcmp(LDB_CONTROL_PAGED_RESULTS_OID
, reply
[i
]->oid
) == 0) {
180 struct ldb_paged_control
*rep_control
, *req_control
;
182 rep_control
= talloc_get_type(reply
[i
]->data
, struct ldb_paged_control
);
183 if (rep_control
->cookie_len
== 0) /* we are done */
186 /* more processing required */
187 /* let's fill in the request control with the new cookie */
189 for (j
= 0; request
[j
]; j
++) {
190 if (strcmp(LDB_CONTROL_PAGED_RESULTS_OID
, request
[j
]->oid
) == 0)
193 /* if there's a reply control we must find a request
194 * control matching it */
195 if (! request
[j
]) return -1;
197 req_control
= talloc_get_type(request
[j
]->data
, struct ldb_paged_control
);
199 if (req_control
->cookie
)
200 talloc_free(req_control
->cookie
);
201 req_control
->cookie
= talloc_memdup(req_control
,
203 rep_control
->cookie_len
);
204 req_control
->cookie_len
= rep_control
->cookie_len
;
211 if (strcmp(LDB_CONTROL_SORT_RESP_OID
, reply
[i
]->oid
) == 0) {
212 struct ldb_sort_resp_control
*rep_control
;
214 rep_control
= talloc_get_type(reply
[i
]->data
, struct ldb_sort_resp_control
);
216 /* check we have a matching control in the request */
217 for (j
= 0; request
[j
]; j
++) {
218 if (strcmp(LDB_CONTROL_SERVER_SORT_OID
, request
[j
]->oid
) == 0)
222 fprintf(stderr
, "Warning Server Sort reply received but no request found\n");
226 /* check the result */
227 if (rep_control
->result
!= 0) {
228 fprintf(stderr
, "Warning: Sorting not performed with error: %d\n", rep_control
->result
);
234 /* no controls matched, throw a warning */
235 fprintf(stderr
, "Unknown reply control oid: %s\n", reply
[i
]->oid
);
242 static int do_search(struct ldb_context
*ldb
,
243 const struct ldb_dn
*basedn
,
244 struct ldb_cmdline
*options
,
245 const char *expression
,
246 const char * const *attrs
)
251 struct ldb_request req
;
252 struct ldb_result
*result
= NULL
;
254 req
.operation
= LDB_REQ_SEARCH
;
255 req
.op
.search
.base
= basedn
;
256 req
.op
.search
.scope
= options
->scope
;
257 req
.op
.search
.tree
= ldb_parse_tree(ldb
, expression
);
258 req
.op
.search
.attrs
= attrs
;
259 req
.op
.search
.res
= NULL
;
260 req
.controls
= parse_controls(ldb
, options
->controls
);
261 if (options
->controls
!= NULL
&& req
.controls
== NULL
) return -1;
267 ret
= ldb_request(ldb
, &req
);
268 if (ret
!= LDB_SUCCESS
) {
269 printf("search failed - %s\n", ldb_errstring(ldb
));
273 result
= req
.op
.search
.res
;
274 printf("# returned %d records\n", result
->count
);
276 if (options
->sorted
) {
277 ldb_qsort(result
->msgs
, ret
, sizeof(struct ldb_message
*),
278 ldb
, (ldb_qsort_cmp_fn_t
)do_compare_msg
);
281 for (i
= 0; i
< result
->count
; i
++, total
++) {
282 struct ldb_ldif ldif
;
283 printf("# record %d\n", total
+ 1);
285 ldif
.changetype
= LDB_CHANGETYPE_NONE
;
286 ldif
.msg
= result
->msgs
[i
];
288 if (options
->sorted
) {
290 * Ensure attributes are always returned in the same
291 * order. For testing, this makes comparison of old
292 * vs. new much easier.
294 ldb_msg_sort_elements(ldif
.msg
);
297 ldb_ldif_write_file(ldb
, stdout
, &ldif
);
300 if (result
->controls
) {
301 if (handle_controls_reply(result
->controls
, req
.controls
) == 1)
306 ret
= talloc_free(result
);
308 fprintf(stderr
, "talloc_free failed\n");
313 req
.op
.search
.res
= NULL
;
320 int main(int argc
, const char **argv
)
322 struct ldb_context
*ldb
;
323 struct ldb_dn
*basedn
= NULL
;
324 const char * const * attrs
= NULL
;
325 struct ldb_cmdline
*options
;
327 const char *expression
= "(objectclass=*)";
329 ldb
= ldb_init(NULL
);
331 options
= ldb_cmdline_process(ldb
, argc
, argv
, usage
);
333 /* the check for '=' is for compatibility with ldapsearch */
334 if (!options
->interactive
&&
336 strchr(options
->argv
[0], '=')) {
337 expression
= options
->argv
[0];
342 if (options
->argc
> 0) {
343 attrs
= (const char * const *)(options
->argv
);
346 if (options
->basedn
!= NULL
) {
347 basedn
= ldb_dn_explode(ldb
, options
->basedn
);
348 if (basedn
== NULL
) {
349 fprintf(stderr
, "Invalid Base DN format\n");
354 if (options
->interactive
) {
356 while (fgets(line
, sizeof(line
), stdin
)) {
357 if (do_search(ldb
, basedn
, options
, line
, attrs
) == -1) {
362 ret
= do_search(ldb
, basedn
, options
, expression
, attrs
);