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 4283 : static int do_compare_msg(struct ldb_message **el1,
48 : struct ldb_message **el2,
49 : void *opaque)
50 : {
51 4283 : 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 626 : static int store_message(struct ldb_message *msg, struct search_context *sctx) {
72 :
73 626 : sctx->store = talloc_realloc(sctx, sctx->store, struct ldb_message *, sctx->num_stored + 2);
74 626 : if (!sctx->store) {
75 0 : fprintf(stderr, "talloc_realloc failed while storing messages\n");
76 0 : return -1;
77 : }
78 :
79 626 : sctx->store[sctx->num_stored] = talloc_move(sctx->store, &msg);
80 626 : sctx->num_stored++;
81 626 : sctx->store[sctx->num_stored] = NULL;
82 :
83 626 : return 0;
84 : }
85 :
86 90 : static int store_referral(char *referral, struct search_context *sctx) {
87 :
88 90 : sctx->refs_store = talloc_realloc(sctx, sctx->refs_store, char *, sctx->refs_stored + 2);
89 90 : if (!sctx->refs_store) {
90 0 : fprintf(stderr, "talloc_realloc failed while storing referrals\n");
91 0 : return -1;
92 : }
93 :
94 90 : sctx->refs_store[sctx->refs_stored] = talloc_move(sctx->refs_store, &referral);
95 90 : sctx->refs_stored++;
96 90 : sctx->refs_store[sctx->refs_stored] = NULL;
97 :
98 90 : return 0;
99 : }
100 :
101 7730 : static int display_message(struct ldb_message *msg, struct search_context *sctx) {
102 593 : struct ldb_ldif ldif;
103 :
104 7730 : sctx->entries++;
105 7730 : printf("# record %d\n", sctx->entries);
106 :
107 7730 : ldif.changetype = LDB_CHANGETYPE_NONE;
108 7730 : ldif.msg = msg;
109 :
110 7730 : 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 626 : ldb_msg_sort_elements(ldif.msg);
117 : }
118 :
119 7730 : ldb_ldif_write_file(sctx->ldb, stdout, &ldif);
120 :
121 7730 : return 0;
122 : }
123 :
124 628 : static int display_referral(char *referral, struct search_context *sctx)
125 : {
126 :
127 628 : sctx->refs++;
128 649 : printf("# Referral\nref: %s\n\n", referral);
129 :
130 628 : return 0;
131 : }
132 :
133 9277 : static int search_callback(struct ldb_request *req, struct ldb_reply *ares)
134 : {
135 721 : struct search_context *sctx;
136 9277 : int ret = LDB_SUCCESS;
137 :
138 9277 : sctx = talloc_get_type(req->context, struct search_context);
139 :
140 9277 : if (!ares) {
141 0 : return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
142 : }
143 9277 : if (ares->error != LDB_SUCCESS) {
144 10 : return ldb_request_done(req, ares->error);
145 : }
146 :
147 9267 : switch (ares->type) {
148 7730 : case LDB_REPLY_ENTRY:
149 7730 : if (sctx->sort) {
150 626 : ret = store_message(ares->message, sctx);
151 : } else {
152 7104 : ret = display_message(ares->message, sctx);
153 : }
154 7137 : break;
155 :
156 628 : case LDB_REPLY_REFERRAL:
157 628 : if (sctx->sort) {
158 90 : ret = store_referral(ares->referral, sctx);
159 : } else {
160 538 : ret = display_referral(ares->referral, sctx);
161 : }
162 628 : if (ret) {
163 0 : return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
164 : }
165 607 : break;
166 :
167 909 : case LDB_REPLY_DONE:
168 909 : if (ares->controls) {
169 44 : if (handle_controls_reply(ares->controls, sctx->req_ctrls) == 1)
170 22 : sctx->pending = 1;
171 : }
172 909 : talloc_free(ares);
173 909 : return ldb_request_done(req, LDB_SUCCESS);
174 : }
175 :
176 8358 : talloc_free(ares);
177 8358 : if (ret != LDB_SUCCESS) {
178 0 : return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
179 : }
180 :
181 7744 : return LDB_SUCCESS;
182 : }
183 :
184 900 : 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 110 : struct ldb_request *req;
191 110 : struct search_context *sctx;
192 110 : int ret;
193 :
194 900 : req = NULL;
195 :
196 900 : sctx = talloc_zero(ldb, struct search_context);
197 900 : if (!sctx) return LDB_ERR_OPERATIONS_ERROR;
198 :
199 900 : sctx->ldb = ldb;
200 900 : sctx->sort = options->sorted;
201 900 : sctx->req_ctrls = ldb_parse_control_strings(ldb, sctx, (const char **)options->controls);
202 900 : 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 900 : again:
208 : /* free any previous requests */
209 922 : if (req) talloc_free(req);
210 :
211 922 : 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 922 : 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 919 : 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 67 : struct ldb_control *ctrl;
231 332 : struct ldb_search_options_control *search_options = NULL;
232 :
233 332 : ctrl = ldb_request_get_control(req, LDB_CONTROL_SEARCH_OPTIONS_OID);
234 332 : if (ctrl) {
235 22 : search_options = talloc_get_type(ctrl->data, struct ldb_search_options_control);
236 : }
237 :
238 332 : if (ctrl == NULL || search_options == NULL ||
239 22 : !(search_options->search_options & LDB_SEARCH_OPTION_PHANTOM_ROOT)) {
240 310 : struct ldb_dn *base = ldb_get_default_basedn(ldb);
241 310 : if (base != NULL) {
242 245 : req->op.search.base = base;
243 : }
244 : }
245 : }
246 :
247 919 : sctx->pending = 0;
248 :
249 919 : ret = ldb_request(ldb, req);
250 919 : 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 919 : ret = ldb_wait(req->handle, LDB_WAIT_ALL);
258 919 : if (ret != LDB_SUCCESS) {
259 10 : talloc_free(sctx);
260 10 : talloc_free(req);
261 10 : printf("search error - %s\n", ldb_errstring(ldb));
262 10 : return ret;
263 : }
264 :
265 909 : if (sctx->pending)
266 22 : goto again;
267 :
268 887 : if (sctx->sort && (sctx->num_stored != 0 || sctx->refs != 0)) {
269 7 : unsigned int i;
270 :
271 46 : if (sctx->num_stored) {
272 46 : LDB_TYPESAFE_QSORT(sctx->store, sctx->num_stored, ldb, do_compare_msg);
273 : }
274 672 : for (i = 0; i < sctx->num_stored; i++) {
275 626 : display_message(sctx->store[i], sctx);
276 : }
277 :
278 136 : for (i = 0; i < sctx->refs_stored; i++) {
279 90 : display_referral(sctx->refs_store[i], sctx);
280 : }
281 : }
282 :
283 887 : printf("# returned %u records\n# %u entries\n# %u referrals\n",
284 790 : sctx->entries + sctx->refs, sctx->entries, sctx->refs);
285 :
286 887 : talloc_free(sctx);
287 887 : talloc_free(req);
288 :
289 887 : return LDB_SUCCESS;
290 : }
291 :
292 926 : int main(int argc, const char **argv)
293 : {
294 111 : struct ldb_context *ldb;
295 926 : struct ldb_dn *basedn = NULL;
296 926 : const char * const * attrs = NULL;
297 111 : struct ldb_cmdline *options;
298 926 : int ret = -1;
299 926 : const char *expression = "(|(objectClass=*)(distinguishedName=*))";
300 926 : TALLOC_CTX *mem_ctx = talloc_new(NULL);
301 :
302 926 : ldb = ldb_init(mem_ctx, NULL);
303 926 : if (ldb == NULL) {
304 0 : return LDB_ERR_OPERATIONS_ERROR;
305 : }
306 :
307 926 : options = ldb_cmdline_process_search(ldb, argc, argv, usage);
308 :
309 : /* the check for '=' is for compatibility with ldapsearch */
310 900 : if (!options->interactive &&
311 900 : options->argc > 0 &&
312 769 : strpbrk(options->argv[0], "=<>~:")) {
313 613 : expression = options->argv[0];
314 613 : options->argv++;
315 613 : options->argc--;
316 : }
317 :
318 900 : if (options->argc > 0) {
319 407 : attrs = (const char * const *)(options->argv);
320 : }
321 :
322 900 : if (options->basedn != NULL) {
323 587 : basedn = ldb_dn_new(ldb, ldb, options->basedn);
324 587 : if (basedn == NULL) {
325 0 : talloc_free(mem_ctx);
326 0 : return LDB_ERR_OPERATIONS_ERROR;
327 : }
328 : }
329 :
330 900 : 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 900 : ret = do_search(ldb, basedn, options, expression, attrs);
337 : }
338 :
339 900 : talloc_free(mem_ctx);
340 :
341 900 : return ret;
342 : }
|