Line data Source code
1 : /*
2 : ldb database library
3 :
4 : Copyright (C) Andrew Tridgell 2004
5 :
6 : ** NOTE! The following LGPL license applies to the ldb
7 : ** library. This does NOT imply that all of Samba is released
8 : ** under the LGPL
9 :
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 3 of the License, or (at your option) any later version.
14 :
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.
19 :
20 : You should have received a copy of the GNU Lesser General Public
21 : License along with this library; if not, see <http://www.gnu.org/licenses/>.
22 : */
23 :
24 : /*
25 : * Name: ldb
26 : *
27 : * Component: ldbsearch
28 : *
29 : * Description: utility for ldb search - modelled on ldapsearch
30 : *
31 : * Author: Andrew Tridgell
32 : */
33 :
34 : #include "replace.h"
35 : #include "system/filesys.h"
36 : #include "system/time.h"
37 : #include "ldb.h"
38 : #include "tools/cmdline.h"
39 :
40 1 : static void usage(struct ldb_context *ldb)
41 : {
42 1 : printf("Usage: ldbsearch <options> <expression> <attrs...>\n");
43 1 : ldb_cmdline_help(ldb, "ldbsearch", stdout);
44 1 : exit(LDB_ERR_OPERATIONS_ERROR);
45 : }
46 :
47 503 : static int do_compare_msg(struct ldb_message **el1,
48 : struct ldb_message **el2,
49 : void *opaque)
50 : {
51 503 : return ldb_dn_compare((*el1)->dn, (*el2)->dn);
52 : }
53 :
54 : struct search_context {
55 : struct ldb_context *ldb;
56 : struct ldb_control **req_ctrls;
57 :
58 : int sort;
59 : unsigned int num_stored;
60 : struct ldb_message **store;
61 : unsigned int refs_stored;
62 : char **refs_store;
63 :
64 : unsigned int entries;
65 : unsigned int refs;
66 :
67 : unsigned int pending;
68 : int status;
69 : };
70 :
71 175 : static int store_message(struct ldb_message *msg, struct search_context *sctx) {
72 :
73 175 : sctx->store = talloc_realloc(sctx, sctx->store, struct ldb_message *, sctx->num_stored + 2);
74 175 : if (!sctx->store) {
75 0 : fprintf(stderr, "talloc_realloc failed while storing messages\n");
76 0 : return -1;
77 : }
78 :
79 175 : sctx->store[sctx->num_stored] = talloc_move(sctx->store, &msg);
80 175 : sctx->num_stored++;
81 175 : sctx->store[sctx->num_stored] = NULL;
82 :
83 175 : return 0;
84 : }
85 :
86 69 : static int store_referral(char *referral, struct search_context *sctx) {
87 :
88 69 : sctx->refs_store = talloc_realloc(sctx, sctx->refs_store, char *, sctx->refs_stored + 2);
89 69 : if (!sctx->refs_store) {
90 0 : fprintf(stderr, "talloc_realloc failed while storing referrals\n");
91 0 : return -1;
92 : }
93 :
94 69 : sctx->refs_store[sctx->refs_stored] = talloc_move(sctx->refs_store, &referral);
95 69 : sctx->refs_stored++;
96 69 : sctx->refs_store[sctx->refs_stored] = NULL;
97 :
98 69 : return 0;
99 : }
100 :
101 6999 : static int display_message(struct ldb_message *msg, struct search_context *sctx) {
102 : struct ldb_ldif ldif;
103 :
104 6999 : sctx->entries++;
105 6999 : printf("# record %d\n", sctx->entries);
106 :
107 6999 : ldif.changetype = LDB_CHANGETYPE_NONE;
108 6999 : ldif.msg = msg;
109 :
110 6999 : if (sctx->sort) {
111 : /*
112 : * Ensure attributes are always returned in the same
113 : * order. For testing, this makes comparison of old
114 : * vs. new much easier.
115 : */
116 175 : ldb_msg_sort_elements(ldif.msg);
117 : }
118 :
119 6999 : ldb_ldif_write_file(sctx->ldb, stdout, &ldif);
120 :
121 6999 : return 0;
122 : }
123 :
124 571 : static int display_referral(char *referral, struct search_context *sctx)
125 : {
126 :
127 571 : sctx->refs++;
128 571 : printf("# Referral\nref: %s\n\n", referral);
129 :
130 571 : return 0;
131 : }
132 :
133 8410 : static int search_callback(struct ldb_request *req, struct ldb_reply *ares)
134 : {
135 : struct search_context *sctx;
136 8410 : int ret = LDB_SUCCESS;
137 :
138 8410 : sctx = talloc_get_type(req->context, struct search_context);
139 :
140 8410 : if (!ares) {
141 0 : return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
142 : }
143 8410 : if (ares->error != LDB_SUCCESS) {
144 2 : return ldb_request_done(req, ares->error);
145 : }
146 :
147 8408 : switch (ares->type) {
148 6999 : case LDB_REPLY_ENTRY:
149 6999 : if (sctx->sort) {
150 175 : ret = store_message(ares->message, sctx);
151 : } else {
152 6824 : ret = display_message(ares->message, sctx);
153 : }
154 6999 : break;
155 :
156 571 : case LDB_REPLY_REFERRAL:
157 571 : if (sctx->sort) {
158 69 : ret = store_referral(ares->referral, sctx);
159 : } else {
160 502 : ret = display_referral(ares->referral, sctx);
161 : }
162 571 : if (ret) {
163 0 : return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
164 : }
165 571 : break;
166 :
167 838 : case LDB_REPLY_DONE:
168 838 : if (ares->controls) {
169 44 : if (handle_controls_reply(ares->controls, sctx->req_ctrls) == 1)
170 22 : sctx->pending = 1;
171 : }
172 838 : talloc_free(ares);
173 838 : return ldb_request_done(req, LDB_SUCCESS);
174 : }
175 :
176 7570 : talloc_free(ares);
177 7570 : if (ret != LDB_SUCCESS) {
178 0 : return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
179 : }
180 :
181 7570 : return LDB_SUCCESS;
182 : }
183 :
184 821 : static int do_search(struct ldb_context *ldb,
185 : struct ldb_dn *basedn,
186 : struct ldb_cmdline *options,
187 : const char *expression,
188 : const char * const *attrs)
189 : {
190 : struct ldb_request *req;
191 : struct search_context *sctx;
192 : int ret;
193 :
194 821 : req = NULL;
195 :
196 821 : sctx = talloc_zero(ldb, struct search_context);
197 821 : if (!sctx) return LDB_ERR_OPERATIONS_ERROR;
198 :
199 821 : sctx->ldb = ldb;
200 821 : sctx->sort = options->sorted;
201 821 : sctx->req_ctrls = ldb_parse_control_strings(ldb, sctx, (const char **)options->controls);
202 821 : if (options->controls != NULL && sctx->req_ctrls== NULL) {
203 0 : printf("parsing controls failed: %s\n", ldb_errstring(ldb));
204 0 : return LDB_ERR_OPERATIONS_ERROR;
205 : }
206 :
207 821 : again:
208 : /* free any previous requests */
209 843 : if (req) talloc_free(req);
210 :
211 843 : ret = ldb_build_search_req(&req, ldb, ldb,
212 : basedn, options->scope,
213 : expression, attrs,
214 : sctx->req_ctrls,
215 : sctx, search_callback,
216 : NULL);
217 843 : if (ret != LDB_SUCCESS) {
218 3 : talloc_free(sctx);
219 3 : printf("allocating request failed: %s\n", ldb_errstring(ldb));
220 3 : return ret;
221 : }
222 :
223 840 : if (basedn == NULL) {
224 : /*
225 : we need to use a NULL base DN when doing a cross-ncs
226 : search so we find results on all partitions in a
227 : forest. When doing a domain-local search, default to
228 : the default basedn
229 : */
230 : struct ldb_control *ctrl;
231 314 : struct ldb_search_options_control *search_options = NULL;
232 :
233 314 : ctrl = ldb_request_get_control(req, LDB_CONTROL_SEARCH_OPTIONS_OID);
234 314 : if (ctrl) {
235 22 : search_options = talloc_get_type(ctrl->data, struct ldb_search_options_control);
236 : }
237 :
238 336 : if (ctrl == NULL || search_options == NULL ||
239 22 : !(search_options->search_options & LDB_SEARCH_OPTION_PHANTOM_ROOT)) {
240 292 : struct ldb_dn *base = ldb_get_default_basedn(ldb);
241 292 : if (base != NULL) {
242 227 : req->op.search.base = base;
243 : }
244 : }
245 : }
246 :
247 840 : sctx->pending = 0;
248 :
249 840 : ret = ldb_request(ldb, req);
250 840 : if (ret != LDB_SUCCESS) {
251 0 : talloc_free(sctx);
252 0 : talloc_free(req);
253 0 : printf("search failed - %s\n", ldb_errstring(ldb));
254 0 : return ret;
255 : }
256 :
257 840 : ret = ldb_wait(req->handle, LDB_WAIT_ALL);
258 840 : if (ret != LDB_SUCCESS) {
259 2 : talloc_free(sctx);
260 2 : talloc_free(req);
261 2 : printf("search error - %s\n", ldb_errstring(ldb));
262 2 : return ret;
263 : }
264 :
265 838 : if (sctx->pending)
266 22 : goto again;
267 :
268 816 : if (sctx->sort && (sctx->num_stored != 0 || sctx->refs != 0)) {
269 : unsigned int i;
270 :
271 39 : if (sctx->num_stored) {
272 39 : LDB_TYPESAFE_QSORT(sctx->store, sctx->num_stored, ldb, do_compare_msg);
273 : }
274 214 : for (i = 0; i < sctx->num_stored; i++) {
275 175 : display_message(sctx->store[i], sctx);
276 : }
277 :
278 108 : for (i = 0; i < sctx->refs_stored; i++) {
279 69 : display_referral(sctx->refs_store[i], sctx);
280 : }
281 : }
282 :
283 1542 : printf("# returned %u records\n# %u entries\n# %u referrals\n",
284 816 : sctx->entries + sctx->refs, sctx->entries, sctx->refs);
285 :
286 816 : talloc_free(sctx);
287 816 : talloc_free(req);
288 :
289 816 : return LDB_SUCCESS;
290 : }
291 :
292 846 : int main(int argc, const char **argv)
293 : {
294 : struct ldb_context *ldb;
295 846 : struct ldb_dn *basedn = NULL;
296 846 : const char * const * attrs = NULL;
297 : struct ldb_cmdline *options;
298 846 : int ret = -1;
299 846 : const char *expression = "(|(objectClass=*)(distinguishedName=*))";
300 846 : TALLOC_CTX *mem_ctx = talloc_new(NULL);
301 :
302 846 : ldb = ldb_init(mem_ctx, NULL);
303 846 : if (ldb == NULL) {
304 0 : return LDB_ERR_OPERATIONS_ERROR;
305 : }
306 :
307 846 : options = ldb_cmdline_process_search(ldb, argc, argv, usage);
308 :
309 : /* the check for '=' is for compatibility with ldapsearch */
310 1552 : if (!options->interactive &&
311 1462 : options->argc > 0 &&
312 719 : strpbrk(options->argv[0], "=<>~:")) {
313 587 : expression = options->argv[0];
314 587 : options->argv++;
315 587 : options->argc--;
316 : }
317 :
318 821 : if (options->argc > 0) {
319 357 : attrs = (const char * const *)(options->argv);
320 : }
321 :
322 821 : if (options->basedn != NULL) {
323 526 : basedn = ldb_dn_new(ldb, ldb, options->basedn);
324 526 : if (basedn == NULL) {
325 0 : talloc_free(mem_ctx);
326 0 : return LDB_ERR_OPERATIONS_ERROR;
327 : }
328 : }
329 :
330 821 : if (options->interactive) {
331 : char line[1024];
332 0 : while (fgets(line, sizeof(line), stdin)) {
333 0 : ret = do_search(ldb, basedn, options, line, attrs);
334 : }
335 : } else {
336 821 : ret = do_search(ldb, basedn, options, expression, attrs);
337 : }
338 :
339 821 : talloc_free(mem_ctx);
340 :
341 821 : return ret;
342 : }
|