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 3175 : static int do_compare_msg(struct ldb_message **el1,
48 : struct ldb_message **el2)
49 : {
50 3175 : return ldb_dn_compare((*el1)->dn, (*el2)->dn);
51 : }
52 :
53 : struct search_context {
54 : struct ldb_context *ldb;
55 : struct ldb_control **req_ctrls;
56 :
57 : int sort;
58 : unsigned int num_stored;
59 : struct ldb_message **store;
60 : unsigned int refs_stored;
61 : char **refs_store;
62 :
63 : unsigned int entries;
64 : unsigned int refs;
65 :
66 : unsigned int pending;
67 : int status;
68 : };
69 :
70 626 : static int store_message(struct ldb_message *msg, struct search_context *sctx) {
71 :
72 626 : sctx->store = talloc_realloc(sctx, sctx->store, struct ldb_message *, sctx->num_stored + 2);
73 626 : if (!sctx->store) {
74 0 : fprintf(stderr, "talloc_realloc failed while storing messages\n");
75 0 : return -1;
76 : }
77 :
78 626 : sctx->store[sctx->num_stored] = talloc_move(sctx->store, &msg);
79 626 : sctx->num_stored++;
80 626 : sctx->store[sctx->num_stored] = NULL;
81 :
82 626 : return 0;
83 : }
84 :
85 90 : static int store_referral(char *referral, struct search_context *sctx) {
86 :
87 90 : sctx->refs_store = talloc_realloc(sctx, sctx->refs_store, char *, sctx->refs_stored + 2);
88 90 : if (!sctx->refs_store) {
89 0 : fprintf(stderr, "talloc_realloc failed while storing referrals\n");
90 0 : return -1;
91 : }
92 :
93 90 : sctx->refs_store[sctx->refs_stored] = talloc_move(sctx->refs_store, &referral);
94 90 : sctx->refs_stored++;
95 90 : sctx->refs_store[sctx->refs_stored] = NULL;
96 :
97 90 : return 0;
98 : }
99 :
100 7821 : static int display_message(struct ldb_message *msg, struct search_context *sctx) {
101 593 : struct ldb_ldif ldif;
102 :
103 7821 : sctx->entries++;
104 7821 : printf("# record %d\n", sctx->entries);
105 :
106 7821 : ldif.changetype = LDB_CHANGETYPE_NONE;
107 7821 : ldif.msg = msg;
108 :
109 7821 : if (sctx->sort) {
110 : /*
111 : * Ensure attributes are always returned in the same
112 : * order. For testing, this makes comparison of old
113 : * vs. new much easier.
114 : */
115 626 : ldb_msg_sort_elements(ldif.msg);
116 : }
117 :
118 7821 : ldb_ldif_write_file(sctx->ldb, stdout, &ldif);
119 :
120 7821 : return 0;
121 : }
122 :
123 628 : static int display_referral(char *referral, struct search_context *sctx)
124 : {
125 :
126 628 : sctx->refs++;
127 649 : printf("# Referral\nref: %s\n\n", referral);
128 :
129 628 : return 0;
130 : }
131 :
132 9459 : static int search_callback(struct ldb_request *req, struct ldb_reply *ares)
133 : {
134 721 : struct search_context *sctx;
135 9459 : int ret = LDB_SUCCESS;
136 :
137 9459 : sctx = talloc_get_type(req->context, struct search_context);
138 :
139 9459 : if (!ares) {
140 0 : return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
141 : }
142 9459 : if (ares->error != LDB_SUCCESS) {
143 10 : return ldb_request_done(req, ares->error);
144 : }
145 :
146 9449 : switch (ares->type) {
147 7821 : case LDB_REPLY_ENTRY:
148 7821 : if (sctx->sort) {
149 626 : ret = store_message(ares->message, sctx);
150 : } else {
151 7195 : ret = display_message(ares->message, sctx);
152 : }
153 7228 : break;
154 :
155 628 : case LDB_REPLY_REFERRAL:
156 628 : if (sctx->sort) {
157 90 : ret = store_referral(ares->referral, sctx);
158 : } else {
159 538 : ret = display_referral(ares->referral, sctx);
160 : }
161 628 : if (ret) {
162 0 : return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
163 : }
164 607 : break;
165 :
166 1000 : case LDB_REPLY_DONE:
167 1000 : if (ares->controls) {
168 44 : if (handle_controls_reply(ares->controls, sctx->req_ctrls) == 1)
169 22 : sctx->pending = 1;
170 : }
171 1000 : talloc_free(ares);
172 1000 : return ldb_request_done(req, LDB_SUCCESS);
173 : }
174 :
175 8449 : talloc_free(ares);
176 8449 : if (ret != LDB_SUCCESS) {
177 0 : return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
178 : }
179 :
180 7835 : return LDB_SUCCESS;
181 : }
182 :
183 991 : static int do_search(struct ldb_context *ldb,
184 : struct ldb_dn *basedn,
185 : struct ldb_cmdline *options,
186 : const char *expression,
187 : const char * const *attrs)
188 : {
189 110 : struct ldb_request *req;
190 110 : struct search_context *sctx;
191 110 : int ret;
192 :
193 991 : req = NULL;
194 :
195 991 : sctx = talloc_zero(ldb, struct search_context);
196 991 : if (!sctx) return LDB_ERR_OPERATIONS_ERROR;
197 :
198 991 : sctx->ldb = ldb;
199 991 : sctx->sort = options->sorted;
200 991 : sctx->req_ctrls = ldb_parse_control_strings(ldb, sctx, (const char **)options->controls);
201 991 : if (options->controls != NULL && sctx->req_ctrls== NULL) {
202 0 : printf("parsing controls failed: %s\n", ldb_errstring(ldb));
203 0 : return LDB_ERR_OPERATIONS_ERROR;
204 : }
205 :
206 991 : again:
207 : /* free any previous requests */
208 1013 : if (req) talloc_free(req);
209 :
210 1013 : ret = ldb_build_search_req(&req, ldb, ldb,
211 : basedn, options->scope,
212 : expression, attrs,
213 : sctx->req_ctrls,
214 : sctx, search_callback,
215 : NULL);
216 1013 : if (ret != LDB_SUCCESS) {
217 3 : talloc_free(sctx);
218 3 : printf("allocating request failed: %s\n", ldb_errstring(ldb));
219 3 : return ret;
220 : }
221 :
222 1010 : if (basedn == NULL) {
223 : /*
224 : we need to use a NULL base DN when doing a cross-ncs
225 : search so we find results on all partitions in a
226 : forest. When doing a domain-local search, default to
227 : the default basedn
228 : */
229 67 : struct ldb_control *ctrl;
230 332 : struct ldb_search_options_control *search_options = NULL;
231 :
232 332 : ctrl = ldb_request_get_control(req, LDB_CONTROL_SEARCH_OPTIONS_OID);
233 332 : if (ctrl) {
234 22 : search_options = talloc_get_type(ctrl->data, struct ldb_search_options_control);
235 : }
236 :
237 332 : if (ctrl == NULL || search_options == NULL ||
238 22 : !(search_options->search_options & LDB_SEARCH_OPTION_PHANTOM_ROOT)) {
239 310 : struct ldb_dn *base = ldb_get_default_basedn(ldb);
240 310 : if (base != NULL) {
241 245 : req->op.search.base = base;
242 : }
243 : }
244 : }
245 :
246 1010 : sctx->pending = 0;
247 :
248 1010 : ret = ldb_request(ldb, req);
249 1010 : if (ret != LDB_SUCCESS) {
250 0 : talloc_free(sctx);
251 0 : talloc_free(req);
252 0 : printf("search failed - %s\n", ldb_errstring(ldb));
253 0 : return ret;
254 : }
255 :
256 1010 : ret = ldb_wait(req->handle, LDB_WAIT_ALL);
257 1010 : if (ret != LDB_SUCCESS) {
258 10 : talloc_free(sctx);
259 10 : talloc_free(req);
260 10 : printf("search error - %s\n", ldb_errstring(ldb));
261 10 : return ret;
262 : }
263 :
264 1000 : if (sctx->pending)
265 22 : goto again;
266 :
267 978 : if (sctx->sort && (sctx->num_stored != 0 || sctx->refs != 0)) {
268 7 : unsigned int i;
269 :
270 46 : if (sctx->num_stored) {
271 46 : TYPESAFE_QSORT(sctx->store, sctx->num_stored, do_compare_msg);
272 : }
273 672 : for (i = 0; i < sctx->num_stored; i++) {
274 626 : display_message(sctx->store[i], sctx);
275 : }
276 :
277 136 : for (i = 0; i < sctx->refs_stored; i++) {
278 90 : display_referral(sctx->refs_store[i], sctx);
279 : }
280 : }
281 :
282 978 : printf("# returned %u records\n# %u entries\n# %u referrals\n",
283 881 : sctx->entries + sctx->refs, sctx->entries, sctx->refs);
284 :
285 978 : talloc_free(sctx);
286 978 : talloc_free(req);
287 :
288 978 : return LDB_SUCCESS;
289 : }
290 :
291 1081 : int main(int argc, const char **argv)
292 : {
293 111 : struct ldb_context *ldb;
294 1081 : struct ldb_dn *basedn = NULL;
295 1081 : const char * const * attrs = NULL;
296 111 : struct ldb_cmdline *options;
297 1081 : int ret = -1;
298 1081 : const char *expression = "(|(objectClass=*)(distinguishedName=*))";
299 1081 : TALLOC_CTX *mem_ctx = talloc_new(NULL);
300 :
301 1081 : ldb = ldb_init(mem_ctx, NULL);
302 1081 : if (ldb == NULL) {
303 0 : return LDB_ERR_OPERATIONS_ERROR;
304 : }
305 :
306 1081 : options = ldb_cmdline_process_search(ldb, argc, argv, usage);
307 :
308 : /* the check for '=' is for compatibility with ldapsearch */
309 991 : if (!options->interactive &&
310 991 : options->argc > 0 &&
311 860 : strpbrk(options->argv[0], "=<>~:")) {
312 613 : expression = options->argv[0];
313 613 : options->argv++;
314 613 : options->argc--;
315 : }
316 :
317 991 : if (options->argc > 0) {
318 498 : attrs = (const char * const *)(options->argv);
319 : }
320 :
321 991 : if (options->basedn != NULL) {
322 678 : basedn = ldb_dn_new(ldb, ldb, options->basedn);
323 678 : if (basedn == NULL) {
324 0 : talloc_free(mem_ctx);
325 0 : return LDB_ERR_OPERATIONS_ERROR;
326 : }
327 : }
328 :
329 991 : if (options->interactive) {
330 : char line[1024];
331 0 : while (fgets(line, sizeof(line), stdin)) {
332 0 : ret = do_search(ldb, basedn, options, line, attrs);
333 : }
334 : } else {
335 991 : ret = do_search(ldb, basedn, options, expression, attrs);
336 : }
337 :
338 991 : talloc_free(mem_ctx);
339 :
340 991 : return ret;
341 : }
|